freesolo-flash-dev 0.2.28__tar.gz → 0.2.30__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 (334) hide show
  1. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/bake-kernel-cache.yml +16 -29
  2. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/Dockerfile.worker +20 -4
  3. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/PKG-INFO +1 -1
  4. freesolo_flash_dev-0.2.30/flash/__init__.py +13 -0
  5. freesolo_flash_dev-0.2.30/flash/_channel.py +11 -0
  6. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/_fileio.py +4 -9
  7. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/_logging.py +4 -16
  8. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/_update_check.py +14 -82
  9. freesolo_flash_dev-0.2.30/flash/catalog.py +264 -0
  10. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cli/__init__.py +44 -13
  11. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cli/commands.py +5 -45
  12. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cli/envpush.py +132 -12
  13. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cli/render.py +32 -63
  14. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cli/training_doc.py +1 -11
  15. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/client/config.py +3 -11
  16. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/client/http.py +82 -133
  17. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/client/runtime_secrets.py +3 -19
  18. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/client/specs.py +1 -5
  19. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cost/__init__.py +1 -2
  20. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cost/analytical.py +8 -13
  21. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cost/facts.py +9 -32
  22. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cost/spec.py +1 -2
  23. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cost/types.py +1 -13
  24. freesolo_flash_dev-0.2.30/flash/engine/__init__.py +1 -0
  25. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/engine/accounting.py +3 -7
  26. freesolo_flash_dev-0.2.30/flash/engine/chalk_kernels.py +65 -0
  27. freesolo_flash_dev-0.2.30/flash/engine/multiturn_rollout.py +598 -0
  28. freesolo_flash_dev-0.2.30/flash/engine/recipe.py +53 -0
  29. freesolo_flash_dev-0.2.30/flash/engine/vram.py +571 -0
  30. freesolo_flash_dev-0.2.30/flash/engine/worker/__init__.py +417 -0
  31. freesolo_flash_dev-0.2.30/flash/engine/worker/_pkg.py +24 -0
  32. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/engine/worker/adapter.py +67 -99
  33. freesolo_flash_dev-0.2.30/flash/engine/worker/decoding.py +69 -0
  34. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/engine/worker/finalize.py +1 -12
  35. freesolo_flash_dev-0.2.30/flash/engine/worker/gpu_setup.py +158 -0
  36. freesolo_flash_dev-0.2.30/flash/engine/worker/grpo.py +225 -0
  37. freesolo_flash_dev-0.2.30/flash/engine/worker/heartbeat.py +240 -0
  38. freesolo_flash_dev-0.2.30/flash/engine/worker/hf.py +477 -0
  39. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/engine/worker/kernel_warmup.py +104 -66
  40. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/engine/worker/lora.py +36 -250
  41. freesolo_flash_dev-0.2.30/flash/engine/worker/packing.py +313 -0
  42. freesolo_flash_dev-0.2.30/flash/engine/worker/perf/__init__.py +363 -0
  43. freesolo_flash_dev-0.2.30/flash/engine/worker/perf/attn.py +107 -0
  44. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/engine/worker/perf/diagnostics.py +6 -20
  45. freesolo_flash_dev-0.2.30/flash/engine/worker/perf/lifecycle.py +240 -0
  46. freesolo_flash_dev-0.2.30/flash/engine/worker/perf/liger.py +49 -0
  47. freesolo_flash_dev-0.2.30/flash/engine/worker/perf/loraplus.py +18 -0
  48. freesolo_flash_dev-0.2.30/flash/engine/worker/perf/memory.py +128 -0
  49. freesolo_flash_dev-0.2.30/flash/engine/worker/rl.py +767 -0
  50. freesolo_flash_dev-0.2.30/flash/engine/worker/sft.py +532 -0
  51. freesolo_flash_dev-0.2.30/flash/engine/worker/wandb_log.py +110 -0
  52. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/envs/adapter.py +244 -238
  53. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/envs/base.py +2 -7
  54. freesolo_flash_dev-0.2.30/flash/envs/pull.py +215 -0
  55. freesolo_flash_dev-0.2.30/flash/envs/registry.py +26 -0
  56. freesolo_flash_dev-0.2.30/flash/providers/__init__.py +37 -0
  57. freesolo_flash_dev-0.2.30/flash/providers/_auth.py +10 -0
  58. freesolo_flash_dev-0.2.30/flash/providers/_http.py +166 -0
  59. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/_instance.py +23 -161
  60. freesolo_flash_dev-0.2.30/flash/providers/_instance_bootstrap.py +384 -0
  61. freesolo_flash_dev-0.2.30/flash/providers/_poll.py +309 -0
  62. freesolo_flash_dev-0.2.30/flash/providers/allocator.py +112 -0
  63. freesolo_flash_dev-0.2.30/flash/providers/base.py +341 -0
  64. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/lambdalabs/__init__.py +4 -35
  65. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/lambdalabs/api.py +12 -73
  66. freesolo_flash_dev-0.2.30/flash/providers/lambdalabs/auth.py +15 -0
  67. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/lambdalabs/gpus.py +1 -6
  68. freesolo_flash_dev-0.2.30/flash/providers/lambdalabs/jobs/__init__.py +617 -0
  69. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/lambdalabs/jobs/builders.py +7 -25
  70. freesolo_flash_dev-0.2.30/flash/providers/lambdalabs/preflight.py +15 -0
  71. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/lambdalabs/pricing.py +2 -9
  72. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/lambdalabs/train.py +1 -8
  73. freesolo_flash_dev-0.2.30/flash/providers/preflight.py +65 -0
  74. freesolo_flash_dev-0.2.30/flash/providers/realized.py +56 -0
  75. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/runpod/__init__.py +11 -31
  76. freesolo_flash_dev-0.2.30/flash/providers/runpod/api.py +212 -0
  77. freesolo_flash_dev-0.2.30/flash/providers/runpod/auth.py +23 -0
  78. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/runpod/cost.py +1 -6
  79. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/runpod/gpus.py +1 -9
  80. freesolo_flash_dev-0.2.30/flash/providers/runpod/jobs.py +801 -0
  81. freesolo_flash_dev-0.2.30/flash/providers/runpod/keys.py +97 -0
  82. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/runpod/preflight.py +1 -7
  83. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/runpod/preload.py +36 -264
  84. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/runpod/slots.py +2 -11
  85. freesolo_flash_dev-0.2.30/flash/providers/runpod/train/__init__.py +62 -0
  86. freesolo_flash_dev-0.2.30/flash/providers/runpod/train/deps.py +239 -0
  87. freesolo_flash_dev-0.2.30/flash/providers/runpod/train/endpoints.py +616 -0
  88. freesolo_flash_dev-0.2.30/flash/runner/__init__.py +525 -0
  89. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/runner/checkpoints.py +1 -1
  90. freesolo_flash_dev-0.2.30/flash/runner/deploy.py +220 -0
  91. freesolo_flash_dev-0.2.30/flash/runner/lifecycle.py +591 -0
  92. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/schema/__init__.py +18 -74
  93. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/schema/fields.py +11 -126
  94. freesolo_flash_dev-0.2.30/flash/serve/deploy.py +309 -0
  95. freesolo_flash_dev-0.2.30/flash/serve/export.py +107 -0
  96. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/serve/pricing.py +2 -7
  97. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/_deps.py +12 -12
  98. freesolo_flash_dev-0.2.30/flash/server/_internal_client.py +58 -0
  99. freesolo_flash_dev-0.2.30/flash/server/_locks.py +55 -0
  100. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/_runtime.py +75 -4
  101. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/app.py +14 -4
  102. freesolo_flash_dev-0.2.30/flash/server/auth.py +206 -0
  103. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/billing.py +11 -39
  104. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/billing_retry.py +10 -9
  105. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/checkpoints.py +14 -49
  106. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/db.py +5 -31
  107. freesolo_flash_dev-0.2.30/flash/server/environment_registry.py +104 -0
  108. freesolo_flash_dev-0.2.30/flash/server/envs.py +603 -0
  109. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/reconcile.py +3 -4
  110. freesolo_flash_dev-0.2.30/flash/server/repo_cleanup.py +296 -0
  111. freesolo_flash_dev-0.2.30/flash/server/routes/__init__.py +1 -0
  112. freesolo_flash_dev-0.2.30/flash/server/routes/envs.py +67 -0
  113. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/routes/meta.py +2 -0
  114. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/routes/runs.py +6 -38
  115. freesolo_flash_dev-0.2.30/flash/server/routes/serving.py +332 -0
  116. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/run_registry.py +7 -18
  117. freesolo_flash_dev-0.2.30/flash/spec.py +246 -0
  118. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/pyproject.toml +2 -2
  119. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/conftest.py +11 -0
  120. freesolo_flash_dev-0.2.30/tests/test_b200_rollout_opt.py +144 -0
  121. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_billing_retry.py +6 -1
  122. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cancel_remote.py +81 -2
  123. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_checkpoints.py +46 -1
  124. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cli_help.py +31 -2
  125. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cli_render_theme.py +24 -0
  126. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_client.py +52 -2
  127. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_client_server_integration.py +2 -0
  128. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cost_analytical.py +10 -8
  129. freesolo_flash_dev-0.2.30/tests/test_env_delete.py +116 -0
  130. freesolo_flash_dev-0.2.30/tests/test_env_publish.py +926 -0
  131. freesolo_flash_dev-0.2.30/tests/test_env_pull.py +625 -0
  132. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_flash_worker.py +49 -5
  133. freesolo_flash_dev-0.2.30/tests/test_flashinfer_cache_dirs.py +54 -0
  134. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_github_urlopen_retry.py +75 -0
  135. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_grpo_params.py +104 -0
  136. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_grpo_sleep_gate.py +94 -0
  137. freesolo_flash_dev-0.2.30/tests/test_internal_client.py +30 -0
  138. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_jobs.py +256 -20
  139. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_kernel_cache.py +8 -14
  140. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_kv_util.py +43 -1
  141. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_lambda_runner.py +84 -4
  142. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_login_perms.py +15 -0
  143. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_mig_guard.py +9 -68
  144. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_multiturn_rollout.py +50 -0
  145. freesolo_flash_dev-0.2.30/tests/test_oom_escalate_gpu.py +121 -0
  146. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_poll_helpers.py +4 -8
  147. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_provider_routing.py +81 -0
  148. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_provider_teardown_robustness.py +0 -18
  149. freesolo_flash_dev-0.2.30/tests/test_repo_cleanup.py +513 -0
  150. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_resume_on_retry.py +23 -7
  151. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_runmgmt.py +33 -30
  152. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_runpod_key_waterfall.py +32 -0
  153. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_serve.py +87 -25
  154. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_server_api.py +345 -21
  155. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_server_billing.py +13 -3
  156. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_server_db.py +3 -1
  157. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_serving_contract.py +14 -6
  158. freesolo_flash_dev-0.2.30/tests/test_sft_gc_off.py +158 -0
  159. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_spec_and_validation.py +49 -11
  160. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_verifiers.py +73 -17
  161. freesolo_flash_dev-0.2.30/tests/test_vl_warmstart_adapter_keys.py +296 -0
  162. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_vl_warmstart_recombine.py +63 -21
  163. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_worker_hardexit.py +42 -0
  164. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_worker_stack.py +51 -16
  165. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/uv.lock +1 -1
  166. freesolo_flash_dev-0.2.28/flash/__init__.py +0 -29
  167. freesolo_flash_dev-0.2.28/flash/_channel.py +0 -28
  168. freesolo_flash_dev-0.2.28/flash/catalog.py +0 -331
  169. freesolo_flash_dev-0.2.28/flash/engine/__init__.py +0 -6
  170. freesolo_flash_dev-0.2.28/flash/engine/chalk_kernels.py +0 -111
  171. freesolo_flash_dev-0.2.28/flash/engine/multiturn_rollout.py +0 -780
  172. freesolo_flash_dev-0.2.28/flash/engine/recipe.py +0 -74
  173. freesolo_flash_dev-0.2.28/flash/engine/vram.py +0 -639
  174. freesolo_flash_dev-0.2.28/flash/engine/worker/__init__.py +0 -599
  175. freesolo_flash_dev-0.2.28/flash/engine/worker/_pkg.py +0 -30
  176. freesolo_flash_dev-0.2.28/flash/engine/worker/decoding.py +0 -144
  177. freesolo_flash_dev-0.2.28/flash/engine/worker/gpu_setup.py +0 -101
  178. freesolo_flash_dev-0.2.28/flash/engine/worker/grpo.py +0 -297
  179. freesolo_flash_dev-0.2.28/flash/engine/worker/heartbeat.py +0 -322
  180. freesolo_flash_dev-0.2.28/flash/engine/worker/hf.py +0 -563
  181. freesolo_flash_dev-0.2.28/flash/engine/worker/packing.py +0 -486
  182. freesolo_flash_dev-0.2.28/flash/engine/worker/perf/__init__.py +0 -495
  183. freesolo_flash_dev-0.2.28/flash/engine/worker/perf/attn.py +0 -176
  184. freesolo_flash_dev-0.2.28/flash/engine/worker/perf/lifecycle.py +0 -274
  185. freesolo_flash_dev-0.2.28/flash/engine/worker/perf/liger.py +0 -73
  186. freesolo_flash_dev-0.2.28/flash/engine/worker/perf/loraplus.py +0 -40
  187. freesolo_flash_dev-0.2.28/flash/engine/worker/perf/memory.py +0 -84
  188. freesolo_flash_dev-0.2.28/flash/engine/worker/rl.py +0 -939
  189. freesolo_flash_dev-0.2.28/flash/engine/worker/sft.py +0 -683
  190. freesolo_flash_dev-0.2.28/flash/engine/worker/wandb_log.py +0 -145
  191. freesolo_flash_dev-0.2.28/flash/envs/registry.py +0 -37
  192. freesolo_flash_dev-0.2.28/flash/providers/__init__.py +0 -54
  193. freesolo_flash_dev-0.2.28/flash/providers/_auth.py +0 -16
  194. freesolo_flash_dev-0.2.28/flash/providers/_http.py +0 -230
  195. freesolo_flash_dev-0.2.28/flash/providers/_instance_bootstrap.py +0 -515
  196. freesolo_flash_dev-0.2.28/flash/providers/_poll.py +0 -444
  197. freesolo_flash_dev-0.2.28/flash/providers/allocator.py +0 -165
  198. freesolo_flash_dev-0.2.28/flash/providers/base.py +0 -442
  199. freesolo_flash_dev-0.2.28/flash/providers/lambdalabs/auth.py +0 -18
  200. freesolo_flash_dev-0.2.28/flash/providers/lambdalabs/jobs/__init__.py +0 -831
  201. freesolo_flash_dev-0.2.28/flash/providers/lambdalabs/preflight.py +0 -27
  202. freesolo_flash_dev-0.2.28/flash/providers/preflight.py +0 -92
  203. freesolo_flash_dev-0.2.28/flash/providers/realized.py +0 -80
  204. freesolo_flash_dev-0.2.28/flash/providers/runpod/api.py +0 -278
  205. freesolo_flash_dev-0.2.28/flash/providers/runpod/auth.py +0 -37
  206. freesolo_flash_dev-0.2.28/flash/providers/runpod/jobs.py +0 -1064
  207. freesolo_flash_dev-0.2.28/flash/providers/runpod/keys.py +0 -145
  208. freesolo_flash_dev-0.2.28/flash/providers/runpod/train/__init__.py +0 -101
  209. freesolo_flash_dev-0.2.28/flash/providers/runpod/train/deps.py +0 -461
  210. freesolo_flash_dev-0.2.28/flash/providers/runpod/train/endpoints.py +0 -830
  211. freesolo_flash_dev-0.2.28/flash/runner/__init__.py +0 -817
  212. freesolo_flash_dev-0.2.28/flash/runner/deploy.py +0 -326
  213. freesolo_flash_dev-0.2.28/flash/runner/lifecycle.py +0 -653
  214. freesolo_flash_dev-0.2.28/flash/serve/deploy.py +0 -332
  215. freesolo_flash_dev-0.2.28/flash/serve/export.py +0 -176
  216. freesolo_flash_dev-0.2.28/flash/server/_locks.py +0 -54
  217. freesolo_flash_dev-0.2.28/flash/server/auth.py +0 -263
  218. freesolo_flash_dev-0.2.28/flash/server/environment_registry.py +0 -102
  219. freesolo_flash_dev-0.2.28/flash/server/envs.py +0 -350
  220. freesolo_flash_dev-0.2.28/flash/server/routes/__init__.py +0 -6
  221. freesolo_flash_dev-0.2.28/flash/server/routes/envs.py +0 -48
  222. freesolo_flash_dev-0.2.28/flash/server/routes/serving.py +0 -427
  223. freesolo_flash_dev-0.2.28/flash/spec.py +0 -338
  224. freesolo_flash_dev-0.2.28/tests/test_env_publish.py +0 -521
  225. freesolo_flash_dev-0.2.28/tests/test_vl_warmstart_adapter_keys.py +0 -581
  226. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.dockerignore +0 -0
  227. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.env.example +0 -0
  228. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/auto-rebake.yml +0 -0
  229. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/ci.yml +0 -0
  230. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/main-source-guard.yml +0 -0
  231. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/publish-dev.yml +0 -0
  232. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/publish-image.yml +0 -0
  233. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/publish.yml +0 -0
  234. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/version-parity.yml +0 -0
  235. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.github/workflows/worker-image.yml +0 -0
  236. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/.gitignore +0 -0
  237. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/Dockerfile +0 -0
  238. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/LICENSE +0 -0
  239. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/README.md +0 -0
  240. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/build/kernel_cache/.gitignore +0 -0
  241. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/build/kernel_cache/.keep +0 -0
  242. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docker/Dockerfile.kernelcache +0 -0
  243. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docker/Dockerfile.kernelcache.relayer +0 -0
  244. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docker/bake_kernel_cache.py +0 -0
  245. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docker/bake_pod_entry.py +0 -0
  246. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docker/kernel_fingerprint.py +0 -0
  247. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docker/make_rp_handler.py +0 -0
  248. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-style/README.md +0 -0
  249. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-style/generate.py +0 -0
  250. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-style/index.html +0 -0
  251. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-style/preview.png +0 -0
  252. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-style/themed-errors.png +0 -0
  253. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-theme/README.md +0 -0
  254. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-theme/before-after-dark.png +0 -0
  255. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-theme/before-after-light.png +0 -0
  256. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-theme/gallery-dark.png +0 -0
  257. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-theme/gallery-light.png +0 -0
  258. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-theme/help-dark.png +0 -0
  259. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/cli-theme/help-light.png +0 -0
  260. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/docs/kernel-cache.md +0 -0
  261. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/cli/__main__.py +0 -0
  262. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/client/__init__.py +0 -0
  263. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/engine/worker/__main__.py +0 -0
  264. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/envs/__init__.py +0 -0
  265. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/providers/runpod/pricing.py +0 -0
  266. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/py.typed +0 -0
  267. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/serve/__init__.py +0 -0
  268. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/__init__.py +0 -0
  269. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/flash/server/__main__.py +0 -0
  270. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/infisical-entrypoint.sh +0 -0
  271. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/scripts/build_dev_dist.py +0 -0
  272. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/__init__.py +0 -0
  273. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/_helpers/__init__.py +0 -0
  274. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/_helpers/runner.py +0 -0
  275. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/_helpers/specs.py +0 -0
  276. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/fixtures/math_eval.jsonl +0 -0
  277. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/fixtures/math_train.jsonl +0 -0
  278. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/live/__init__.py +0 -0
  279. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/live/conftest.py +0 -0
  280. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/live/test_lambda_live.py +0 -0
  281. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/live/test_runpod_live.py +0 -0
  282. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_agent_flash_cli_contract.py +0 -0
  283. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_algorithms.py +0 -0
  284. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_allocator.py +0 -0
  285. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_backend_jobspec_contract.py +0 -0
  286. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_catalog_consistency.py +0 -0
  287. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_chalk_kernels.py +0 -0
  288. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cli_commands.py +0 -0
  289. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cli_errors.py +0 -0
  290. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cli_estimate.py +0 -0
  291. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cli_managed.py +0 -0
  292. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_config_overrides.py +0 -0
  293. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cost_equation.py +0 -0
  294. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cost_estimate.py +0 -0
  295. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cost_hardware.py +0 -0
  296. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cost_models.py +0 -0
  297. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_cost_rewards.py +0 -0
  298. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_dev_channel.py +0 -0
  299. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_disk_gb.py +0 -0
  300. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_endpoint_name.py +0 -0
  301. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_env_no_install.py +0 -0
  302. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_env_push.py +0 -0
  303. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_env_rate_limit_resolve.py +0 -0
  304. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_envs_coverage.py +0 -0
  305. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_export.py +0 -0
  306. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_flash_mvp.py +0 -0
  307. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_gpus.py +0 -0
  308. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_grpo_mask_aware.py +0 -0
  309. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_idle_endpoint_reaper.py +0 -0
  310. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_kernel_fingerprint.py +0 -0
  311. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_logging.py +0 -0
  312. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_managed_hf_repo.py +0 -0
  313. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_metrics_schema_agent_contract.py +0 -0
  314. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_open_model_policy.py +0 -0
  315. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_orchestrator_flash.py +0 -0
  316. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_packing.py +0 -0
  317. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_preflight.py +0 -0
  318. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_providers_symmetry.py +0 -0
  319. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_realized_cost.py +0 -0
  320. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_resolve_params_b.py +0 -0
  321. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_runpod_api_delete.py +0 -0
  322. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_runpod_key_fingerprint.py +0 -0
  323. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_runpod_slots.py +0 -0
  324. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_thinking_config.py +0 -0
  325. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_update_check.py +0 -0
  326. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_version.py +0 -0
  327. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_vl_weight_sync.py +0 -0
  328. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_wandb_naming.py +0 -0
  329. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_warmstart_cross_repo.py +0 -0
  330. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_weight_cache.py +0 -0
  331. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_worker_dryrun.py +0 -0
  332. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_worker_image.py +0 -0
  333. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_worker_init_heartbeat.py +0 -0
  334. {freesolo_flash_dev-0.2.28 → freesolo_flash_dev-0.2.30}/tests/test_worker_thinking.py +0 -0
@@ -11,8 +11,8 @@ name: flash worker kernel-cache (per-arch)
11
11
  # warmup runs INSIDE it so the cache matches the image's pinned torch/triton/fla/liger toolchain.
12
12
  #
13
13
  # Secrets: RUNPOD_API_KEY (the warmup GPU pod) + HF_TOKEN (the temp dataset that ferries code + the
14
- # cache artifact) are pulled from Infisical (/flash, prod) via the bootstrap INFISICAL_CLIENT_ID /
15
- # CLIENT_SECRET / PROJECT_ID repo secrets; the GHCR push uses the default GITHUB_TOKEN. Heavy + paid,
14
+ # cache artifact) are native repo Actions secrets, synced from Infisical (prod:/flash-ci) by the
15
+ # github-ci-flash Secret Sync; the GHCR push uses the default GITHUB_TOKEN. Heavy + paid,
16
16
  # but UNGATED: the fingerprint detection in auto-rebake.yml decides WHEN this runs (only on a real
17
17
  # kernel-toolchain change), so there is no manual approval step. Invoked by hand (workflow_dispatch)
18
18
  # OR automatically by auto-rebake.yml (workflow_call) when the kernel toolchain changed.
@@ -179,38 +179,25 @@ jobs:
179
179
  if: steps.gate.outputs.run == 'true'
180
180
  run: uv sync --extra server
181
181
 
182
- - name: Install Infisical CLI
183
- if: steps.gate.outputs.run == 'true'
184
- run: |
185
- curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | sudo -E bash
186
- sudo apt-get update && sudo apt-get install -y infisical
187
-
188
- # RUNPOD_API_KEY + HF_TOKEN come from Infisical (/flash, prod) -- mirrors infisical-entrypoint.sh;
189
- # the CLI takes the project UUID directly (the secrets-action wants a slug). `env -u
190
- # FLASH_CHALK_SPEC` drops any chalk-spec override living in /flash so the bake always warms the
191
- # repo-default chalk (the value the fingerprint hashed) -- otherwise the image could be warmed with
192
- # one chalk and labeled with another. BASE_IMAGE is digest-pinned so the warm runs inside the EXACT
193
- # base the per-arch tag will sit on.
182
+ # RUNPOD_API_KEY (the warmup GPU pod) + HF_TOKEN (the temp dataset that ferries code/cache) are
183
+ # native repo Actions secrets, synced from Infisical (prod:/flash-ci) by the github-ci-flash
184
+ # Secret Sync. No Infisical CLI/login at job time -- Infisical stays the source of truth and
185
+ # rotations propagate via the sync. FLASH_CHALK_SPEC isn't synced, so bake_kernel_cache.py uses
186
+ # the repo-default DEFAULT_CHALK_SPEC (the value the fingerprint hashed) automatically. BASE_IMAGE
187
+ # is digest-pinned so the warm runs inside the EXACT base the per-arch tag will sit on.
194
188
  - name: Warm kernels on a RunPod ${{ matrix.sm }} GPU -> build/kernel_cache
195
189
  if: steps.gate.outputs.run == 'true'
196
190
  env:
197
- INFISICAL_CLIENT_ID: ${{ secrets.INFISICAL_CLIENT_ID }}
198
- INFISICAL_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET }}
199
- INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
191
+ RUNPOD_API_KEY: ${{ secrets.RUNPOD_API_KEY }}
192
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
200
193
  BASE_IMAGE: ${{ steps.base.outputs.ref }}
201
194
  run: |
202
- INFISICAL_TOKEN="$(infisical login --method=universal-auth \
203
- --client-id="$INFISICAL_CLIENT_ID" --client-secret="$INFISICAL_CLIENT_SECRET" \
204
- --silent --plain)"
205
- export INFISICAL_TOKEN
206
- infisical run --projectId "$INFISICAL_PROJECT_ID" --env prod --path /flash -- \
207
- env -u FLASH_CHALK_SPEC \
208
- uv run python docker/bake_kernel_cache.py \
209
- --arch "${{ matrix.arch }}" --sm "${{ matrix.sm }}" \
210
- --gpu-type-id "${{ matrix.gpu_type_id }}" \
211
- --allowed-cuda "${{ matrix.allowed_cuda }}" \
212
- --image "$BASE_IMAGE" \
213
- --out build/kernel_cache
195
+ uv run python docker/bake_kernel_cache.py \
196
+ --arch "${{ matrix.arch }}" --sm "${{ matrix.sm }}" \
197
+ --gpu-type-id "${{ matrix.gpu_type_id }}" \
198
+ --allowed-cuda "${{ matrix.allowed_cuda }}" \
199
+ --image "$BASE_IMAGE" \
200
+ --out build/kernel_cache
214
201
 
215
202
  - name: Free disk space
216
203
  if: steps.gate.outputs.run == 'true'
@@ -25,9 +25,22 @@ ENV DEBIAN_FRONTEND=noninteractive \
25
25
  # JIT on a cold worker writes here too. These ENVs are always set (cheap); whether the dir is
26
26
  # pre-populated is what the opt-in bake controls. engine.worker._load_kernel_cache_if_present reads
27
27
  # /opt/flash/kernelcache at boot.
28
+ # FLASHINFER_CUBIN_DIR / FLASHINFER_CACHE_DIR / FLASHINFER_WORKSPACE_BASE: FlashInfer's attention-backend
29
+ # cubins (the Blackwell sm120 / B200 rollout attention backend) are NOT bundled in the wheel — flashinfer
30
+ # downloads them from NVIDIA Artifactory on first use. Bake the cubin store + JIT cache into the same
31
+ # persistent kernelcache tree so
32
+ # a baked/volume cache serves them and a cold worker never re-fetches from Artifactory (kernel_warmup
33
+ # also sets these). FLASHINFER_WORKSPACE_BASE is the var flashinfer 0.6.x actually reads to relocate the
34
+ # JIT host-wrapper cache (FLASHINFER_CACHE_DIR is a DERIVED constant there, not an env knob), so set it
35
+ # too — otherwise a B200 path that touches flashinfer before kernel_warmup runs lands the wrapper under
36
+ # the default home workspace and re-JITs instead of using the baked cache.
28
37
  ENV TRITON_CACHE_DIR=/opt/flash/kernelcache/triton \
29
- TORCHINDUCTOR_CACHE_DIR=/opt/flash/kernelcache/inductor
30
- RUN mkdir -p /opt/flash/kernelcache/triton /opt/flash/kernelcache/inductor
38
+ TORCHINDUCTOR_CACHE_DIR=/opt/flash/kernelcache/inductor \
39
+ FLASHINFER_CUBIN_DIR=/opt/flash/kernelcache/flashinfer_cubin \
40
+ FLASHINFER_CACHE_DIR=/opt/flash/kernelcache/flashinfer \
41
+ FLASHINFER_WORKSPACE_BASE=/opt/flash/kernelcache/flashinfer
42
+ RUN mkdir -p /opt/flash/kernelcache/triton /opt/flash/kernelcache/inductor \
43
+ /opt/flash/kernelcache/flashinfer_cubin /opt/flash/kernelcache/flashinfer
31
44
 
32
45
  # build-essential for Triton/Inductor (Liger) + any source builds; git for pip VCS installs.
33
46
  RUN apt-get update && apt-get install -y --no-install-recommends build-essential git curl \
@@ -39,6 +52,7 @@ RUN pip install --no-cache-dir \
39
52
  "trl>=1.6,<1.7" \
40
53
  "peft>=0.19" \
41
54
  "vllm==0.19.1" \
55
+ "flashinfer-python==0.6.6" \
42
56
  "bitsandbytes>=0.49" \
43
57
  "datasets>=4.7,<6" \
44
58
  "huggingface_hub>=0.25" \
@@ -187,10 +201,12 @@ fa_ok = False; \
187
201
  exec('try:\n import flash_attn\n fa_ok = True\nexcept Exception:\n fa_ok = False'); \
188
202
  fa3_ok = False; \
189
203
  exec('try:\n import flash_attn_interface\n fa3_ok = True\nexcept Exception:\n fa3_ok = False'); \
204
+ fi_ok = False; \
205
+ exec('try:\n import flashinfer\n fi_ok = True\nexcept Exception:\n fi_ok = False'); \
190
206
  cudnn = torch.backends.cudnn.version(); assert cudnn, 'cuDNN not compiled into torch'; \
191
207
  ver = lambda n: M.version(n); \
192
- print('worker stack OK | torch', torch.__version__, '| cudnn', cudnn, '| triton', triton.__version__, '| flash_attn', 'present' if fa_ok else 'ABSENT (SDPA fallback)', '| flash_attn_3', 'present (Hopper FA3)' if fa3_ok else 'ABSENT (SDPA on Hopper)'); \
193
- [print(' ', d, ver(d)) for d in ['transformers','trl','peft','vllm','datasets','huggingface-hub', \
208
+ print('worker stack OK | torch', torch.__version__, '| cudnn', cudnn, '| triton', triton.__version__, '| flash_attn', 'present' if fa_ok else 'ABSENT (SDPA fallback)', '| flash_attn_3', 'present (Hopper FA3)' if fa3_ok else 'ABSENT (SDPA on Hopper)', '| flashinfer', 'present (B200 MoE/attn)' if fi_ok else 'ABSENT (Triton fused-MoE fallback)'); \
209
+ [print(' ', d, ver(d)) for d in ['transformers','trl','peft','vllm','flashinfer-python','datasets','huggingface-hub', \
194
210
  'accelerate','wandb','liger-kernel','flash-linear-attention','bitsandbytes', \
195
211
  'hf-transfer','freesolo','runpod']]"
196
212
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freesolo-flash-dev
3
- Version: 0.2.28
3
+ Version: 0.2.30
4
4
  Summary: Flash — managed LoRA post-training (SFT/GRPO) for Freesolo environments, driven by the `flash` CLI
5
5
  Project-URL: Homepage, https://github.com/freesolo-co/flash
6
6
  Project-URL: Repository, https://github.com/freesolo-co/flash
@@ -0,0 +1,13 @@
1
+ """Flash — managed LoRA post-training: log in with your freesolo key, train."""
2
+
3
+ from importlib.metadata import version as _dist_version
4
+
5
+ from flash._channel import DIST_NAME as _DIST_NAME
6
+
7
+ __all__ = ["__version__"]
8
+
9
+ # Read from dist metadata so version literal doesn't drift from pyproject (caused a nag loop in 0.2.20).
10
+ try:
11
+ __version__ = _dist_version(_DIST_NAME)
12
+ except Exception:
13
+ __version__ = "0+unknown"
@@ -0,0 +1,11 @@
1
+ """Single switch between prod and dev channels; ``scripts/build_dev_dist.py`` rewrites CHANNEL to "dev"."""
2
+
3
+ from __future__ import annotations
4
+
5
+ CHANNEL = "dev"
6
+
7
+ # Must stay in lockstep with [project.scripts] in pyproject.toml.
8
+ CLI_NAME = "flash-dev" if CHANNEL == "dev" else "flash"
9
+
10
+ # Must stay in lockstep with [project].name in pyproject.toml.
11
+ DIST_NAME = "freesolo-flash-dev" if CHANNEL == "dev" else "freesolo-flash"
@@ -9,21 +9,16 @@ from pathlib import Path
9
9
 
10
10
 
11
11
  def read_json_or_empty(path: Path) -> dict:
12
- """Parse a JSON object file, returning ``{}`` if it's missing or unreadable."""
12
+ """Parse a JSON object file, returning ``{}`` on any error or if the root is not a dict."""
13
13
  try:
14
- return json.loads(path.read_text())
14
+ data = json.loads(path.read_text())
15
15
  except (OSError, ValueError):
16
16
  return {}
17
+ return data if isinstance(data, dict) else {}
17
18
 
18
19
 
19
20
  def secure_json_write(path: Path, data: dict) -> None:
20
- """Write ``data`` as JSON with private permissions (the file may hold a secret).
21
-
22
- Creates the parent dir (0700) and opens the file 0600 from the start — never
23
- write_text + chmod, which leaves it umask-readable in between. ``O_NOFOLLOW``
24
- (where available) refuses to follow a symlink planted at ``path`` so the write
25
- can't be redirected to clobber an arbitrary file.
26
- """
21
+ """Write ``data`` as JSON 0600. Opens with O_CREAT|0o600 never write_text+chmod (TOCTOU). O_NOFOLLOW blocks symlink redirect."""
27
22
  path.parent.mkdir(parents=True, exist_ok=True)
28
23
  with contextlib.suppress(OSError):
29
24
  os.chmod(path.parent, 0o700)
@@ -1,10 +1,4 @@
1
- """Package logging helpers.
2
-
3
- Library code logs through the ``flash`` logger and never configures handlers on import (it
4
- attaches a :class:`logging.NullHandler`), so importing Flash stays silent for downstream
5
- applications. The CLI calls :func:`configure_logging` to attach a console handler whose
6
- level is controlled by ``-v/--verbose``.
7
- """
1
+ """Package logging helpers."""
8
2
 
9
3
  from __future__ import annotations
10
4
 
@@ -12,8 +6,7 @@ import logging
12
6
 
13
7
  _ROOT_NAME = "flash"
14
8
 
15
- # Attach a NullHandler once so "No handlers could be found" warnings never appear and
16
- # importing the library produces no output unless the app opts in.
9
+ # NullHandler: keep library import silent; app opts in via configure_logging.
17
10
  _root = logging.getLogger(_ROOT_NAME)
18
11
  if not any(isinstance(h, logging.NullHandler) for h in _root.handlers):
19
12
  _root.addHandler(logging.NullHandler())
@@ -29,20 +22,15 @@ def get_logger(name: str | None = None) -> logging.Logger:
29
22
 
30
23
 
31
24
  def configure_logging(verbosity: int = 0, level: int | None = None) -> None:
32
- """Attach a console handler to the ``flash`` logger and set its level.
33
-
34
- ``verbosity`` maps repeated ``-v`` flags to levels (0=WARNING, 1=INFO, >=2=DEBUG).
35
- An explicit ``level`` overrides the verbosity mapping.
36
- """
25
+ """Attach a console handler to the ``flash`` logger and set its level."""
37
26
  if level is None:
38
27
  level = {0: logging.WARNING, 1: logging.INFO}.get(verbosity, logging.DEBUG)
39
28
 
40
29
  logger = logging.getLogger(_ROOT_NAME)
41
30
  logger.setLevel(level)
42
- # Replace any prior console handler we installed so repeated calls don't stack handlers.
43
31
  for h in [h for h in logger.handlers if getattr(h, "_flash_console", False)]:
44
32
  logger.removeHandler(h)
45
- handler = logging.StreamHandler() # stderr
33
+ handler = logging.StreamHandler()
46
34
  handler.setLevel(level)
47
35
  handler.setFormatter(logging.Formatter("%(levelname)s %(name)s: %(message)s"))
48
36
  handler._flash_console = True # type: ignore[attr-defined]
@@ -1,23 +1,4 @@
1
- """Background "a new release is available" notice for the `flash` CLI.
2
-
3
- The client CLI is pure standard library (no extra deps), so this is too: it queries PyPI
4
- with ``urllib`` and compares the published version against the installed ``__version__``.
5
-
6
- Design constraints that keep it from ever getting in the way:
7
-
8
- - **Stays out of the way.** The PyPI lookup runs in a daemon thread (so it overlaps the
9
- command) and every failure (offline, timeout, bad JSON) is swallowed. Only the once-a-day
10
- refresh waits briefly for that thread; every other command builds the notice from cache with
11
- zero network I/O.
12
- - **Cached once per day.** The latest version is stored in ``~/.flash/update_check.json``;
13
- we only hit PyPI when that cache is older than :data:`_CHECK_INTERVAL_S`. The check time is
14
- stamped synchronously before the lookup so the daily back-off holds even if the worker thread
15
- is killed at process exit before it records a result.
16
- - **stderr only, TTY only.** The notice prints to stderr (never stdout), so it can't corrupt
17
- JSON piped to ``jq`` or captured output, and it's suppressed entirely when stderr isn't a
18
- terminal (pipes, redirects, CI, tests). Color is dropped when ``NO_COLOR`` is set.
19
- - **Opt-out.** Set ``FLASH_NO_UPDATE_CHECK=1`` to disable the check and notice completely.
20
- """
1
+ """Background "a new release is available" notice for the `flash` CLI."""
21
2
 
22
3
  from __future__ import annotations
23
4
 
@@ -39,32 +20,23 @@ from flash.client.config import CONFIG_DIR
39
20
 
40
21
  logger = get_logger("flash.update_check")
41
22
 
42
- # The PyPI distribution name (== pyproject `name`) and the command that upgrades it. Follows the
43
- # installed channel (freesolo-flash, or freesolo-flash-dev for the dev build) — see flash/_channel.py.
44
23
  PACKAGE_NAME = DIST_NAME
45
24
  UPGRADE_COMMAND = f"uv tool upgrade {PACKAGE_NAME}"
46
25
  _PYPI_JSON_URL = f"https://pypi.org/pypi/{PACKAGE_NAME}/json"
47
26
 
48
27
  CACHE_PATH = CONFIG_DIR / "update_check.json"
49
28
 
50
- # Re-check PyPI at most once a day; the notice itself is shown on every command from cache.
51
29
  _CHECK_INTERVAL_S = 24 * 60 * 60
52
- # How long the lookup may take, and how long the once-a-day refresh waits for it at the end of a
53
- # command. Keep the join >= the fetch timeout so the worker thread finishes (and records its
54
- # result) within the wait instead of being killed at process exit mid-write.
30
+ # join >= fetch timeout so the worker finishes writing before process exit kills it.
55
31
  _FETCH_TIMEOUT_S = 1.5
56
32
  _JOIN_TIMEOUT_S = 2.0
57
33
 
58
34
  _OPT_OUT_ENV = "FLASH_NO_UPDATE_CHECK"
59
35
 
60
- # A PEP 440 version only uses this charset. We reject anything else (control chars, ANSI escape
61
- # sequences, newlines) before printing the value to a terminal, so a poisoned cache or a hostile
62
- # response can't inject escape codes into the notice. The length bound is just a sanity cap.
36
+ # Reject anything outside the PEP 440 charset before printing prevents escape-code injection.
63
37
  _SAFE_VERSION = re.compile(r"\A[A-Za-z0-9][A-Za-z0-9.+!_-]{0,63}\Z")
64
38
 
65
- # A coarse subset of the PEP 440 grammar: the numeric release plus optional pre/post/dev markers.
66
- # Enough to order the simple versions this package ships and to spot pre-releases; this is not a
67
- # full PEP 440 implementation (the stdlib-only client can't depend on `packaging`).
39
+ # Coarse PEP 440 subset; stdlib-only client can't depend on `packaging`.
68
40
  _VERSION_RE = re.compile(
69
41
  r"""\A\s*v?
70
42
  (?P<release>\d+(?:\.\d+)*)
@@ -77,14 +49,12 @@ _VERSION_RE = re.compile(
77
49
 
78
50
 
79
51
  def _enabled() -> bool:
80
- """The whole feature is off unless stderr is a TTY and the user hasn't opted out."""
52
+ """Off unless stderr is a TTY and the user hasn't opted out."""
81
53
  if os.environ.get(_OPT_OUT_ENV):
82
54
  return False
83
55
  try:
84
56
  return bool(sys.stderr.isatty())
85
57
  except Exception:
86
- # stderr may be detached/closed/replaced (e.g. some embedded contexts); any failure
87
- # here is treated as "not a TTY" so the check can never crash a command.
88
58
  return False
89
59
 
90
60
 
@@ -97,13 +67,7 @@ def _normalize_release(release: tuple[int, ...]) -> tuple[int, ...]:
97
67
 
98
68
 
99
69
  def _version_key(version: str) -> tuple[tuple[int, ...], int, int]:
100
- """A coarse PEP 440 sort key ``(release, final_rank, post)`` where higher means newer.
101
-
102
- The release segment is normalized (``1.0 == 1.0.0``). A pre-release/dev version ranks below
103
- the final release of the same number (``final_rank`` 0 vs 1); a post-release ranks above it
104
- via ``post``. Epochs and local versions are ignored — the catalog ships only simple versions.
105
- Returns an empty release for unparseable input, which compares as "older than everything".
106
- """
70
+ """Sort key ``(release, final_rank, post)`` where higher means newer."""
107
71
  match = _VERSION_RE.match(version or "")
108
72
  if not match:
109
73
  return ((), 1, 0)
@@ -127,19 +91,12 @@ def _is_newer(latest: str, current: str) -> bool:
127
91
 
128
92
 
129
93
  def _clean_version(value: object) -> str | None:
130
- """Return ``value`` only if it's a safe, escape-free version string, else ``None``.
131
-
132
- Guards both the PyPI response and the on-disk cache: ``_version_key`` parses just the
133
- numeric/marker prefix, so without this an injected suffix (ANSI codes, newlines) could reach
134
- the terminal. Non-strings (and anything outside the PEP 440 charset) are rejected.
135
- """
94
+ """Return ``value`` if it's a safe version string, else ``None``."""
136
95
  return value if isinstance(value, str) and _SAFE_VERSION.match(value) else None
137
96
 
138
97
 
139
98
  def _read_cache() -> dict:
140
- # read_json_or_empty returns whatever the file parses to; a non-object (e.g. ``[]``) would
141
- # make the ``.get()`` callers raise, and _check_due runs before main()'s error handling — so
142
- # coerce anything that isn't a dict back to an empty one.
99
+ # Coerce non-dict results (e.g. []) since _check_due runs before main()'s error handling.
143
100
  cache = read_json_or_empty(CACHE_PATH)
144
101
  return cache if isinstance(cache, dict) else {}
145
102
 
@@ -168,21 +125,13 @@ def _fetch_latest_version(timeout: float = _FETCH_TIMEOUT_S) -> str | None:
168
125
  except (urllib.error.URLError, OSError, ValueError, TimeoutError) as exc:
169
126
  logger.debug("update check: PyPI lookup failed: %s", exc)
170
127
  return None
171
- # Expected shape is {"info": {"version": ...}}; tolerate anything else (a proxy error page,
172
- # ``[]``, ``{"info": null}``, ...) instead of letting a dereference raise into the caller.
173
128
  info = payload.get("info") if isinstance(payload, dict) else None
174
129
  version = info.get("version") if isinstance(info, dict) else None
175
130
  return _clean_version(version)
176
131
 
177
132
 
178
133
  def _stamp_check_time() -> None:
179
- """Record "checked just now" (keeping any cached version), synchronously and best-effort.
180
-
181
- Done before the background lookup starts so the daily back-off holds even if the daemon worker
182
- is killed at process exit before it records its own result — otherwise a stale/missing cache
183
- would make every command re-run (and wait on) the lookup. Never raises (runs before main()'s
184
- error handling).
185
- """
134
+ """Record "checked just now" synchronously so the daily back-off holds even if the daemon is killed."""
186
135
  with contextlib.suppress(Exception):
187
136
  cache = _read_cache()
188
137
  cache["checked_at"] = time.time()
@@ -190,11 +139,7 @@ def _stamp_check_time() -> None:
190
139
 
191
140
 
192
141
  def _refresh_cache() -> None:
193
- """Fetch from PyPI and persist the version on success; runs in a daemon thread, never raises.
194
-
195
- The attempt time is already stamped by :func:`_stamp_check_time`, so a failed lookup just
196
- returns and lets the daily back-off (set there) stand.
197
- """
142
+ """Fetch from PyPI and persist the version; runs in a daemon thread, never raises."""
198
143
  try:
199
144
  latest = _fetch_latest_version()
200
145
  if not latest:
@@ -203,7 +148,7 @@ def _refresh_cache() -> None:
203
148
  cache["checked_at"] = time.time()
204
149
  cache["pypi_version"] = latest
205
150
  secure_json_write(CACHE_PATH, cache)
206
- except Exception as exc: # truly never let a background thread escape
151
+ except Exception as exc:
207
152
  logger.debug("update check: refresh failed: %s", exc)
208
153
 
209
154
 
@@ -218,7 +163,6 @@ def _red(text: str) -> str:
218
163
  def _build_notice() -> str | None:
219
164
  """Build the upgrade notice from the cached PyPI version, or ``None`` if up to date."""
220
165
  latest = _clean_version(_read_cache().get("pypi_version"))
221
- # Only nudge toward stable releases: never advertise a pre-release (rc/dev) as an upgrade.
222
166
  if not latest or _is_prerelease(latest) or not _is_newer(latest, __version__):
223
167
  return None
224
168
  return _red(
@@ -228,38 +172,26 @@ def _build_notice() -> str | None:
228
172
 
229
173
 
230
174
  def maybe_start_update_check() -> threading.Thread | None:
231
- """Kick off a background PyPI refresh if one is due. Returns the thread (or ``None``).
232
-
233
- Pass the return value to :func:`emit_update_notice`. No-ops (returns ``None``) when the
234
- feature is disabled or the cached check is still fresh, so the common path is free.
235
- """
175
+ """Kick off a background PyPI refresh if one is due; returns the thread (or ``None``)."""
236
176
  if not _enabled() or not _check_due(time.time()):
237
177
  return None
238
- # Stamp the attempt synchronously before spawning the worker, so the daily back-off holds even
239
- # if the daemon is killed at process exit before it writes (see _stamp_check_time).
240
178
  _stamp_check_time()
241
179
  thread = threading.Thread(target=_refresh_cache, name="flash-update-check", daemon=True)
242
180
  try:
243
181
  thread.start()
244
182
  except RuntimeError:
245
- # can't spawn a thread (e.g. interpreter shutting down) — skip the check silently.
246
183
  return None
247
184
  return thread
248
185
 
249
186
 
250
187
  def emit_update_notice(notifier: threading.Thread | None = None) -> None:
251
- """Print the upgrade notice (if any) to stderr at the end of a command.
252
-
253
- Briefly waits for an in-flight refresh so a freshly fetched version can be shown the same
254
- run; if it doesn't finish in time we just use whatever is already cached.
255
- """
188
+ """Print the upgrade notice (if any) to stderr at the end of a command."""
256
189
  if not _enabled():
257
190
  return
258
191
  if notifier is not None:
259
192
  with contextlib.suppress(RuntimeError):
260
193
  notifier.join(timeout=_JOIN_TIMEOUT_S)
261
- # This runs from main()'s finally block, so it must never raise: a broken pipe
262
- # (`flash ... | head`), full disk, or closed stderr would otherwise crash the command.
194
+ # Must never raise: broken pipe or closed stderr would crash the command.
263
195
  with contextlib.suppress(Exception):
264
196
  notice = _build_notice()
265
197
  if notice: