freesolo-flash-dev 0.2.56__tar.gz → 0.2.58__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 (354) hide show
  1. freesolo_flash_dev-0.2.58/.claude/skills/verify/SKILL.md +11 -0
  2. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/auto-rebake.yml +3 -3
  3. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/bake-kernel-cache.yml +1 -1
  4. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/worker-image.yml +8 -9
  5. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/Dockerfile.worker +10 -10
  6. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/PKG-INFO +7 -1
  7. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/docker/bake_kernel_cache.py +1 -1
  8. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/docker/kernel_fingerprint.py +76 -1
  9. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/_channel.py +0 -2
  10. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/_fileio.py +1 -1
  11. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/_update_check.py +5 -15
  12. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/adapter_artifacts.py +0 -2
  13. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/catalog.py +71 -34
  14. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/__init__.py +8 -17
  15. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/commands.py +140 -59
  16. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/envpush.py +2 -4
  17. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/render.py +27 -22
  18. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/training_doc.py +100 -33
  19. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/client/config.py +6 -4
  20. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/client/http.py +104 -64
  21. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/client/runtime_secrets.py +2 -7
  22. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/client/specs.py +7 -1
  23. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cost/analytical.py +77 -18
  24. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cost/facts.py +36 -19
  25. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cost/spec.py +31 -23
  26. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cost/types.py +31 -7
  27. freesolo_flash_dev-0.2.58/flash/diagnostics.py +41 -0
  28. freesolo_flash_dev-0.2.58/flash/engine/accounting.py +79 -0
  29. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/multiturn_rollout.py +165 -39
  30. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/recipe.py +0 -9
  31. freesolo_flash_dev-0.2.58/flash/engine/steps.py +79 -0
  32. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/vram.py +116 -10
  33. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/__init__.py +100 -18
  34. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/adapter.py +57 -15
  35. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/finalize.py +13 -11
  36. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/gpu_setup.py +5 -0
  37. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/grpo.py +1 -0
  38. freesolo_flash_dev-0.2.58/flash/engine/worker/hf.py +846 -0
  39. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/lora.py +11 -3
  40. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/opd.py +733 -364
  41. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/opd_gkd.py +1 -3
  42. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/opd_vllm.py +45 -11
  43. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/packing.py +30 -8
  44. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/perf/lifecycle.py +28 -5
  45. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/perf/liger.py +8 -2
  46. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/perf/memory.py +6 -4
  47. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/rl.py +78 -29
  48. freesolo_flash_dev-0.2.58/flash/engine/worker/rng.py +83 -0
  49. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/sft.py +136 -33
  50. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/teacher.py +36 -13
  51. freesolo_flash_dev-0.2.58/flash/engine/worker_entrypoint.py +22 -0
  52. freesolo_flash_dev-0.2.58/flash/envs/archive.py +71 -0
  53. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/envs/loader.py +25 -111
  54. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/envs/pull.py +8 -1
  55. freesolo_flash_dev-0.2.58/flash/lora_rank.py +357 -0
  56. freesolo_flash_dev-0.2.58/flash/opd_retry_contract.py +266 -0
  57. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/__init__.py +9 -8
  58. freesolo_flash_dev-0.2.58/flash/providers/_deadline.py +51 -0
  59. freesolo_flash_dev-0.2.58/flash/providers/_hf_artifacts.py +350 -0
  60. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_hf_retry.py +19 -4
  61. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_http.py +64 -26
  62. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_instance.py +181 -102
  63. freesolo_flash_dev-0.2.58/flash/providers/_instance_bootstrap.py +944 -0
  64. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_instance_poll.py +267 -117
  65. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_instance_provider.py +25 -15
  66. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_poll.py +33 -27
  67. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_worker.py +64 -60
  68. freesolo_flash_dev-0.2.58/flash/providers/allocator.py +164 -0
  69. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/base.py +33 -8
  70. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/lambdalabs/__init__.py +12 -10
  71. freesolo_flash_dev-0.2.58/flash/providers/lambdalabs/api.py +322 -0
  72. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/lambdalabs/jobs/__init__.py +231 -74
  73. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/lambdalabs/jobs/builders.py +25 -12
  74. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/lambdalabs/pricing.py +2 -2
  75. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/__init__.py +59 -13
  76. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/api.py +81 -42
  77. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/jobs.py +245 -81
  78. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/preload.py +76 -59
  79. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/train/endpoints.py +376 -260
  80. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/vast/__init__.py +13 -12
  81. freesolo_flash_dev-0.2.58/flash/providers/vast/api.py +479 -0
  82. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/vast/jobs/__init__.py +322 -135
  83. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/vast/jobs/builders.py +20 -8
  84. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/vast/pricing.py +39 -7
  85. freesolo_flash_dev-0.2.58/flash/runner/__init__.py +1667 -0
  86. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/runner/checkpoints.py +19 -35
  87. freesolo_flash_dev-0.2.58/flash/runner/deploy.py +1036 -0
  88. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/runner/lifecycle.py +306 -133
  89. freesolo_flash_dev-0.2.58/flash/runner/verified_revisions.py +168 -0
  90. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/schema/__init__.py +219 -84
  91. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/schema/fields.py +23 -12
  92. freesolo_flash_dev-0.2.58/flash/serve/deploy.py +866 -0
  93. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/serve/export.py +26 -12
  94. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/serve/pricing.py +0 -20
  95. freesolo_flash_dev-0.2.58/flash/serve/urls.py +26 -0
  96. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/_internal_client.py +2 -8
  97. freesolo_flash_dev-0.2.58/flash/server/_locks.py +76 -0
  98. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/_runtime.py +56 -22
  99. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/app.py +12 -11
  100. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/auth.py +4 -9
  101. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/billing.py +1 -1
  102. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/checkpoints.py +2 -3
  103. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/reconcile.py +3 -4
  104. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/repo_cleanup.py +1 -1
  105. freesolo_flash_dev-0.2.58/flash/server/routes/runs.py +311 -0
  106. freesolo_flash_dev-0.2.58/flash/server/routes/serving.py +1183 -0
  107. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/run_registry.py +37 -0
  108. freesolo_flash_dev-0.2.58/flash/spec.py +436 -0
  109. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/pyproject.toml +16 -9
  110. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_agent_flash_cli_contract.py +2 -1
  111. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_allocator.py +166 -10
  112. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_backend_jobspec_contract.py +5 -4
  113. freesolo_flash_dev-0.2.58/tests/test_base_model_provenance.py +94 -0
  114. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_billing_retry.py +5 -2
  115. freesolo_flash_dev-0.2.58/tests/test_cancel_remote.py +2182 -0
  116. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_checkpoints.py +107 -16
  117. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cli_commands.py +237 -17
  118. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cli_estimate.py +118 -5
  119. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cli_help.py +6 -0
  120. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cli_render_coverage.py +3 -1
  121. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cli_render_theme.py +22 -15
  122. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_client.py +199 -3
  123. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_config_overrides.py +42 -3
  124. freesolo_flash_dev-0.2.58/tests/test_controlled_experiment_repairs.py +395 -0
  125. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cost_analytical.py +39 -0
  126. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cost_estimate.py +251 -0
  127. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_cache_evict.py +20 -0
  128. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_pull.py +1 -1
  129. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_pull_loader_coverage.py +36 -0
  130. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_export.py +30 -0
  131. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_flash_mvp.py +10 -2
  132. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_flash_worker.py +42 -5
  133. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_gpus.py +15 -0
  134. freesolo_flash_dev-0.2.58/tests/test_hf_retry.py +69 -0
  135. freesolo_flash_dev-0.2.58/tests/test_instance_bootstrap_coverage.py +1846 -0
  136. freesolo_flash_dev-0.2.58/tests/test_internal_client.py +22 -0
  137. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_jobs.py +1704 -360
  138. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_kernel_fingerprint.py +120 -13
  139. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_lambda_api_coverage.py +73 -19
  140. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_lambda_runner.py +955 -199
  141. freesolo_flash_dev-0.2.58/tests/test_lora_rank_preflight.py +298 -0
  142. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_managed_hf_repo.py +2 -2
  143. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_multiturn_rollout.py +135 -130
  144. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_multiturn_rollout_coverage.py +125 -163
  145. freesolo_flash_dev-0.2.58/tests/test_multiturn_rollout_records.py +218 -0
  146. freesolo_flash_dev-0.2.58/tests/test_multiturn_rollout_request_policy.py +353 -0
  147. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_oom_escalate_gpu.py +102 -26
  148. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_opd.py +882 -232
  149. freesolo_flash_dev-0.2.58/tests/test_opd_full_state_resume.py +1161 -0
  150. freesolo_flash_dev-0.2.58/tests/test_opd_resume_safety.py +1224 -0
  151. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_opd_vllm.py +65 -9
  152. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_orchestrator_flash.py +15 -7
  153. freesolo_flash_dev-0.2.58/tests/test_poll_helpers.py +138 -0
  154. freesolo_flash_dev-0.2.58/tests/test_provider_routing.py +1114 -0
  155. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_provider_teardown_robustness.py +0 -13
  156. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_providers_symmetry.py +59 -30
  157. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_realized_cost.py +40 -12
  158. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_repo_cleanup.py +41 -0
  159. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_resume_on_retry.py +377 -28
  160. freesolo_flash_dev-0.2.58/tests/test_runmgmt.py +1836 -0
  161. freesolo_flash_dev-0.2.58/tests/test_runpod_api_delete.py +67 -0
  162. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_runpod_key_fingerprint.py +44 -3
  163. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_serve.py +561 -20
  164. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_server_api.py +2415 -138
  165. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_server_billing.py +76 -6
  166. freesolo_flash_dev-0.2.58/tests/test_server_envs_coverage.py +863 -0
  167. freesolo_flash_dev-0.2.58/tests/test_serving_contract.py +782 -0
  168. freesolo_flash_dev-0.2.58/tests/test_sft_max_context.py +60 -0
  169. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_spec_and_validation.py +383 -18
  170. freesolo_flash_dev-0.2.58/tests/test_training_controls.py +676 -0
  171. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_vast_api.py +358 -57
  172. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_vast_api_coverage.py +56 -7
  173. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_vast_offers.py +68 -11
  174. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_vast_runner.py +1145 -132
  175. freesolo_flash_dev-0.2.58/tests/test_verified_revisions.py +201 -0
  176. freesolo_flash_dev-0.2.58/tests/test_warmstart_cross_repo.py +745 -0
  177. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_weight_cache.py +614 -281
  178. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_worker_hardexit.py +150 -0
  179. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_worker_image.py +12 -13
  180. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_worker_init_heartbeat.py +1 -1
  181. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_worker_stack.py +438 -3
  182. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/uv.lock +19 -7
  183. freesolo_flash_dev-0.2.56/flash/engine/accounting.py +0 -38
  184. freesolo_flash_dev-0.2.56/flash/engine/steps.py +0 -18
  185. freesolo_flash_dev-0.2.56/flash/engine/worker/hf.py +0 -489
  186. freesolo_flash_dev-0.2.56/flash/lora_rank.py +0 -203
  187. freesolo_flash_dev-0.2.56/flash/providers/_hf_artifacts.py +0 -177
  188. freesolo_flash_dev-0.2.56/flash/providers/_instance_bootstrap.py +0 -525
  189. freesolo_flash_dev-0.2.56/flash/providers/allocator.py +0 -100
  190. freesolo_flash_dev-0.2.56/flash/providers/lambdalabs/api.py +0 -200
  191. freesolo_flash_dev-0.2.56/flash/providers/runpod/train/deps.py +0 -19
  192. freesolo_flash_dev-0.2.56/flash/providers/vast/api.py +0 -314
  193. freesolo_flash_dev-0.2.56/flash/runner/__init__.py +0 -835
  194. freesolo_flash_dev-0.2.56/flash/runner/deploy.py +0 -364
  195. freesolo_flash_dev-0.2.56/flash/serve/deploy.py +0 -501
  196. freesolo_flash_dev-0.2.56/flash/server/_locks.py +0 -43
  197. freesolo_flash_dev-0.2.56/flash/server/routes/runs.py +0 -180
  198. freesolo_flash_dev-0.2.56/flash/server/routes/serving.py +0 -641
  199. freesolo_flash_dev-0.2.56/flash/spec.py +0 -257
  200. freesolo_flash_dev-0.2.56/tests/test_cancel_remote.py +0 -835
  201. freesolo_flash_dev-0.2.56/tests/test_instance_bootstrap_coverage.py +0 -453
  202. freesolo_flash_dev-0.2.56/tests/test_internal_client.py +0 -30
  203. freesolo_flash_dev-0.2.56/tests/test_lora_rank_preflight.py +0 -142
  204. freesolo_flash_dev-0.2.56/tests/test_poll_helpers.py +0 -91
  205. freesolo_flash_dev-0.2.56/tests/test_provider_routing.py +0 -573
  206. freesolo_flash_dev-0.2.56/tests/test_runmgmt.py +0 -420
  207. freesolo_flash_dev-0.2.56/tests/test_runpod_api_delete.py +0 -90
  208. freesolo_flash_dev-0.2.56/tests/test_server_envs_coverage.py +0 -436
  209. freesolo_flash_dev-0.2.56/tests/test_serving_contract.py +0 -395
  210. freesolo_flash_dev-0.2.56/tests/test_warmstart_cross_repo.py +0 -104
  211. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.dockerignore +0 -0
  212. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.env.example +0 -0
  213. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/ci.yml +0 -0
  214. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/main-source-guard.yml +0 -0
  215. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/notify-tests-repo.yml +0 -0
  216. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/publish-dev.yml +0 -0
  217. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/publish-image.yml +0 -0
  218. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/publish.yml +0 -0
  219. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.github/workflows/version-parity.yml +0 -0
  220. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/.gitignore +0 -0
  221. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/Dockerfile +0 -0
  222. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/LICENSE +0 -0
  223. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/README.md +0 -0
  224. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/build/kernel_cache/.gitignore +0 -0
  225. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/build/kernel_cache/.keep +0 -0
  226. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/docker/Dockerfile.kernelcache +0 -0
  227. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/docker/Dockerfile.kernelcache.relayer +0 -0
  228. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/docker/bake_pod_entry.py +0 -0
  229. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/docker/make_rp_handler.py +0 -0
  230. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/__init__.py +0 -0
  231. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/_logging.py +0 -0
  232. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/__main__.py +0 -0
  233. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/_tty.py +0 -0
  234. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cli/env_setup.py +0 -0
  235. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/client/__init__.py +0 -0
  236. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/cost/__init__.py +0 -0
  237. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/__init__.py +0 -0
  238. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/chalk_kernels.py +0 -0
  239. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/structured_outputs.py +0 -0
  240. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/__main__.py +0 -0
  241. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/_pkg.py +0 -0
  242. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/decoding.py +0 -0
  243. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/heartbeat.py +0 -0
  244. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/kernel_warmup.py +0 -0
  245. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/perf/__init__.py +0 -0
  246. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/perf/attn.py +0 -0
  247. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/perf/diagnostics.py +0 -0
  248. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/perf/loraplus.py +0 -0
  249. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/tokenizer_align.py +0 -0
  250. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/engine/worker/wandb_log.py +0 -0
  251. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/envs/__init__.py +0 -0
  252. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/envs/adapter.py +0 -0
  253. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/envs/archive_policy.py +0 -0
  254. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/envs/base.py +0 -0
  255. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/envs/registry.py +0 -0
  256. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/_auth.py +0 -0
  257. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/lambdalabs/auth.py +0 -0
  258. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/lambdalabs/gpus.py +0 -0
  259. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/lambdalabs/preflight.py +0 -0
  260. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/preflight.py +0 -0
  261. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/realized.py +0 -0
  262. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/auth.py +0 -0
  263. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/cost.py +0 -0
  264. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/gpus.py +0 -0
  265. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/keys.py +0 -0
  266. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/preflight.py +0 -0
  267. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/pricing.py +0 -0
  268. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/slots.py +0 -0
  269. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/runpod/train/__init__.py +0 -0
  270. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/vast/auth.py +0 -0
  271. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/providers/vast/preflight.py +0 -0
  272. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/py.typed +0 -0
  273. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/serve/__init__.py +0 -0
  274. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/__init__.py +0 -0
  275. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/__main__.py +0 -0
  276. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/_deps.py +0 -0
  277. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/billing_retry.py +0 -0
  278. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/db.py +0 -0
  279. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/environment_registry.py +0 -0
  280. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/envs.py +0 -0
  281. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/routes/__init__.py +0 -0
  282. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/routes/envs.py +0 -0
  283. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/flash/server/routes/meta.py +0 -0
  284. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/infisical-entrypoint.sh +0 -0
  285. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/scripts/build_dev_dist.py +0 -0
  286. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/__init__.py +0 -0
  287. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/_helpers/__init__.py +0 -0
  288. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/_helpers/runner.py +0 -0
  289. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/_helpers/specs.py +0 -0
  290. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/_helpers/vast.py +0 -0
  291. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/conftest.py +0 -0
  292. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/fixtures/math_eval.jsonl +0 -0
  293. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/fixtures/math_train.jsonl +0 -0
  294. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/live/__init__.py +0 -0
  295. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/live/conftest.py +0 -0
  296. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/live/test_lambda_live.py +0 -0
  297. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/live/test_runpod_live.py +0 -0
  298. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/live/test_vast_live.py +0 -0
  299. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_algorithms.py +0 -0
  300. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_b200_rollout_opt.py +0 -0
  301. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_catalog_consistency.py +0 -0
  302. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_chalk_kernels.py +0 -0
  303. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_charge_pricing.py +0 -0
  304. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cli_errors.py +0 -0
  305. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cli_managed.py +0 -0
  306. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_client_server_integration.py +0 -0
  307. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cost_equation.py +0 -0
  308. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cost_hardware.py +0 -0
  309. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cost_models.py +0 -0
  310. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_cost_rewards.py +0 -0
  311. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_dev_channel.py +0 -0
  312. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_disk_gb.py +0 -0
  313. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_endpoint_name.py +0 -0
  314. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_delete.py +0 -0
  315. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_download.py +0 -0
  316. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_download_api.py +0 -0
  317. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_no_install.py +0 -0
  318. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_publish.py +0 -0
  319. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_pull_managed_control_plane.py +0 -0
  320. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_push.py +0 -0
  321. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_env_rate_limit_resolve.py +0 -0
  322. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_envs_coverage.py +0 -0
  323. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_flashinfer_cache_dirs.py +0 -0
  324. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_github_urlopen_retry.py +0 -0
  325. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_grpo_mask_aware.py +0 -0
  326. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_grpo_params.py +0 -0
  327. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_grpo_sleep_gate.py +0 -0
  328. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_health_liveness.py +0 -0
  329. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_idle_endpoint_reaper.py +0 -0
  330. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_kernel_cache.py +0 -0
  331. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_kv_util.py +0 -0
  332. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_logging.py +0 -0
  333. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_login_perms.py +0 -0
  334. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_metrics_schema_agent_contract.py +0 -0
  335. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_mig_guard.py +0 -0
  336. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_open_model_policy.py +0 -0
  337. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_packing.py +0 -0
  338. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_preflight.py +0 -0
  339. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_resolve_params_b.py +0 -0
  340. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_runpod_key_waterfall.py +0 -0
  341. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_runpod_slots.py +0 -0
  342. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_server_db.py +0 -0
  343. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_sft_example_selection.py +0 -0
  344. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_sft_gc_off.py +0 -0
  345. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_structured_outputs.py +0 -0
  346. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_thinking_config.py +0 -0
  347. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_train_context_preflight.py +0 -0
  348. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_update_check.py +0 -0
  349. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_verifiers.py +0 -0
  350. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_version.py +0 -0
  351. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  352. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_wandb_naming.py +0 -0
  353. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_worker_dryrun.py +0 -0
  354. {freesolo_flash_dev-0.2.56 → freesolo_flash_dev-0.2.58}/tests/test_worker_thinking.py +0 -0
@@ -0,0 +1,11 @@
1
+ # flash verification
2
+
3
+ Use isolated loopback services to exercise the public FastAPI and CLI surfaces.
4
+
5
+ 1. set `HOME` to a temporary directory so run JSON and `server.db` stay isolated.
6
+ 2. launch a synthetic serving backend on an unused localhost port that implements `/adapters` and `/v1/chat/completions` and records request paths.
7
+ 3. launch `flash.server.app.create_app()` with uvicorn through a temporary launcher. patch startup credential and external-provider preflights only, and set `FREESOLO_INTERNAL_KEY`, `FLASH_DEPLOY_SYNC=1`, and `FREESOLO_SERVING_URL` to the synthetic backend.
8
+ 4. drive the real HTTP routes with curl using the internal bearer key. create dry-run records through `POST /v1/runs`; when a completed artifact is needed, edit only the isolated temporary run JSON before driving deploy, chat, list, cancel, and undeploy routes.
9
+ 5. capture API response bodies and the synthetic backend request log. stop both loopback processes after verification.
10
+
11
+ Use `uv run --project <repo> python ...` for all Python launchers. Never use production credentials or network services.
@@ -105,9 +105,9 @@ jobs:
105
105
  FP_BASE: ${{ steps.base.outputs.fp_base }}
106
106
  REV: ${{ steps.base.outputs.revision }}
107
107
  run: |
108
- # arch list is the single source of truth in deps.py (mirrored by the bake matrix; a test
109
- # pins that mirror). textual parse -> no flash import / uv sync needed.
110
- arches=$(python3 -c "import re,pathlib; t=pathlib.Path('flash/providers/runpod/train/deps.py').read_text(); m=re.search(r'BAKED_PER_SM_ARCHES\s*=\s*frozenset\(\{([^}]+)\}\)', t); print(' '.join(re.findall(r'sm\d+', m.group(1))))")
108
+ # flash/providers/_worker.py is the single source of truth for the arch list; the bake
109
+ # matrix mirrors it. read the canonical assignment statically without importing flash.
110
+ arches=$(python3 docker/kernel_fingerprint.py --print-baked-arches)
111
111
  relayer=(); gpu=()
112
112
  summary="| arch | published fp_cache | published fp_base | action |\n|---|---|---|---|\n"
113
113
  for sm in $arches; do
@@ -5,7 +5,7 @@ name: flash worker kernel-cache (per-arch)
5
5
  # 1. offloads the warmup to a RunPod GPU of that arch (GH runners have none) -> build/kernel_cache,
6
6
  # 2. docker build --build-arg BUILD_KERNEL_CACHE=true -> ghcr.io/freesolo-co/flash-worker:cu128-<sm>,
7
7
  # 3. pushes it. The allocator then selects the cu128-<sm> tag per GPU class for baked arches
8
- # (see flash/providers/runpod/train/deps.py).
8
+ # (see flash/providers/_worker.py).
9
9
  #
10
10
  # Depends on the base ghcr.io/freesolo-co/flash-worker:cu128 image existing (worker-image.yml) — the
11
11
  # warmup runs INSIDE it so the cache matches the image's pinned torch/triton/fla/liger toolchain.
@@ -1,11 +1,10 @@
1
1
  name: flash worker image
2
2
 
3
- # Builds the prebuilt flash worker image (full training stack + flash-attn baked in) and
4
- # pushes it to GHCR, so Vast/RunPod cold-start skips the per-host dep install (the dominant
5
- # cold-start cost). Training and serving both default to the pinned WORKER_IMAGE constant
6
- # (flash/providers/runpod/train.py) bump that to the new tag. FLASH_WORKER_IMAGE is an
7
- # operator env override honored by BOTH training (providers/runpod/{jobs,train}.py) and serving
8
- # (flash/serve/deploy.py).
3
+ # builds the prebuilt flash worker image (full training stack + flash-attn baked in) and
4
+ # pushes it to ghcr, so runpod/vast/lambda training cold-start skips the per-host dependency
5
+ # install (the dominant cold-start cost). training providers select the pinned image and operator
6
+ # override through flash/providers/_worker.py. serving has no consumer for this training-worker
7
+ # image or override.
9
8
  #
10
9
  # Triggered automatically on flash/** changes (worker training code is baked in; skipping a
11
10
  # rebuild leaves GPU workers running stale code) and manually for Dockerfile/dep changes.
@@ -95,9 +94,9 @@ jobs:
95
94
  context: .
96
95
  file: Dockerfile.worker
97
96
  push: true
98
- # Pin the freesolo-co namespace: both RunPod and Vast pull the hardcoded
99
- # WORKER_IMAGE = ghcr.io/freesolo-co/flash-worker:cu128 (flash/providers/runpod/train.py),
100
- # so a fork run must not push to its own owner namespace and leave the real image stale.
97
+ # pin the freesolo-co namespace: runpod, vast, and lambda training paths pull the image
98
+ # declared in flash/providers/_worker.py, so a fork run must not push to its own owner
99
+ # namespace and leave the real image stale.
101
100
  tags: ghcr.io/freesolo-co/flash-worker:${{ github.event.inputs.tag || 'cu128' }}
102
101
  provenance: false
103
102
  # Stamp the kernel-cache fingerprints + the source commit so auto-rebake.yml can read what
@@ -1,7 +1,7 @@
1
1
  # Flash prebuilt WORKER image — the full training stack baked in for RunPod workers.
2
2
  # The worker still fetches the flash `code/**` from HF at runtime, so only DEPS live here.
3
3
  #
4
- # This image is referenced by name in flash/providers/runpod/train/deps.py:WORKER_IMAGE. It MUST be
4
+ # this image name is defined in flash/providers/_worker.py. it must be
5
5
  # published to GHCR and the package set PUBLIC (no registry login is configured) so RunPod can
6
6
  # pull it. Normally built by
7
7
  # .github/workflows/worker-image.yml (manual dispatch); to build/push by hand:
@@ -12,7 +12,7 @@
12
12
  #
13
13
  # Base is torch 2.10 / cu12.8 / cudnn9 (-devel = has nvcc for any source builds); it ships the
14
14
  # CUDA 12.8 runtime libs the PyPI wheels link against. The pinned stack mirrors
15
- # flash/providers/runpod/train/deps.py:WORKER_DEPS.
15
+ # flash/providers/_worker.py:WORKER_DEPS.
16
16
  FROM pytorch/pytorch:2.10.0-cuda12.8-cudnn9-devel
17
17
 
18
18
  ENV DEBIAN_FRONTEND=noninteractive \
@@ -78,7 +78,7 @@ RUN pip install --no-cache-dir \
78
78
  # pure-PyTorch fallback (H100 SXM, Qwen3.5 hidden-2560 LoRA): seq4096 4.2x faster / 1.6x less mem,
79
79
  # seq16384 12.6x / 1.9x, loss matches to 1.8e-4. fla is from git: the PyPI wheel is a broken stub
80
80
  # (no fla.modules). The git URL is PINNED to a commit (not the moving default branch) for
81
- # reproducible image builds keep this SHA in lockstep with flash/providers/runpod/train/deps.py:WORKER_DEPS.
81
+ # reproducible image builds; keep this sha in lockstep with the worker dependencies in flash/providers/_worker.py.
82
82
 
83
83
  # FlashAttention: PREFER a prebuilt wheel. There is no OFFICIAL Dao-AILab wheel for torch 2.10 yet,
84
84
  # but community CI publishes matching wheels (cu128/torch2.10/cp312); CI passes one as FLASH_ATTN_SPEC
@@ -144,13 +144,13 @@ RUN TORCH_CUDA_ARCH_LIST="8.0 8.6 8.9 9.0 10.0 12.0" CAUSAL_CONV1D_FORCE_BUILD=T
144
144
  || { echo "causal_conv1d: build/import failed -> removing + GDN packing stays off (Qwen3.5/3.6 train unpacked)"; \
145
145
  pip uninstall -y causal-conv1d 2>/dev/null || true; }
146
146
 
147
- # Weight cache (this PR, RUNTIME not baked): when the shared weight-cache network volume is attached
148
- # (flash runner._assign_weight_cache_volume), the control plane points HF_HOME at the persistent mount
149
- # per-run (providers/.../deps.weight_cache_env), so the MODEL DOWNLOAD is reused across runs landing in
150
- # the same region. ONLY HF_HOME (inert model blobs) is redirected — the executable kernel-JIT caches
151
- # below are deliberately NOT shared (the volume is multi-tenant; a poisoned compiled artifact could
152
- # affect another tenant). The redirect can't be a static image ENV: the volume mounts at a fixed path
153
- # only at runtime and only when attached, so a baked ENV would break cache-less (no-volume) cold runs.
147
+ # weight cache (runtime, not baked): when the shared weight-cache network volume is attached,
148
+ # flash/providers/_worker.py:weight_cache_env redirects only base-model prefetching through
149
+ # FLASH_WEIGHT_CACHE_DIR to the persistent volume for reuse across runs. HF_HOME remains ephemeral,
150
+ # so environment and reward downloads are not shared. executable kernel-jit caches are deliberately
151
+ # not shared because the volume is multi-tenant; a poisoned compiled artifact could affect another
152
+ # tenant. the redirect cannot be a static image environment variable: the volume mounts at a fixed
153
+ # path only at runtime and only when attached, so a baked redirect would break cache-less cold runs.
154
154
  #
155
155
  # Compiled-kernel cache: OPT-IN bake, JIT fallback. The fused Triton (fla/chalk),
156
156
  # TorchInductor, and Hopper tilelang kernels the trainer builds on first use are content-addressed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freesolo-flash-dev
3
- Version: 0.2.56
3
+ Version: 0.2.58
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
@@ -21,8 +21,11 @@ Requires-Dist: fastapi; extra == 'dev'
21
21
  Requires-Dist: freesolo>=0.2.54; extra == 'dev'
22
22
  Requires-Dist: httpx>=0.27; extra == 'dev'
23
23
  Requires-Dist: huggingface-hub>=0.34; extra == 'dev'
24
+ Requires-Dist: jsonschema>=4.23; extra == 'dev'
24
25
  Requires-Dist: mypy>=1.13.0; extra == 'dev'
25
26
  Requires-Dist: pytest>=9.0.3; extra == 'dev'
27
+ Requires-Dist: referencing>=0.28.4; extra == 'dev'
28
+ Requires-Dist: regex>=2024.11.6; extra == 'dev'
26
29
  Requires-Dist: ruff>=0.6; extra == 'dev'
27
30
  Requires-Dist: runpod-flash; extra == 'dev'
28
31
  Requires-Dist: transformers<5.11,>=5.6; extra == 'dev'
@@ -44,6 +47,9 @@ Requires-Dist: fastapi; extra == 'server'
44
47
  Requires-Dist: freesolo>=0.2.54; extra == 'server'
45
48
  Requires-Dist: httpx>=0.27; extra == 'server'
46
49
  Requires-Dist: huggingface-hub>=0.34; extra == 'server'
50
+ Requires-Dist: jsonschema>=4.23; extra == 'server'
51
+ Requires-Dist: referencing>=0.28.4; extra == 'server'
52
+ Requires-Dist: regex>=2024.11.6; extra == 'server'
47
53
  Requires-Dist: runpod-flash; extra == 'server'
48
54
  Requires-Dist: transformers<5.11,>=5.6; extra == 'server'
49
55
  Requires-Dist: uvicorn; extra == 'server'
@@ -105,7 +105,7 @@ def main() -> int:
105
105
  chalk_spec = os.environ.get("FLASH_CHALK_SPEC", "").strip()
106
106
  if not chalk_spec:
107
107
  try:
108
- from flash.providers.runpod.train.deps import DEFAULT_CHALK_SPEC
108
+ from flash.providers._worker import DEFAULT_CHALK_SPEC
109
109
 
110
110
  chalk_spec = DEFAULT_CHALK_SPEC
111
111
  except Exception as exc:
@@ -58,6 +58,8 @@ LABEL_REVISION = "org.opencontainers.image.revision"
58
58
  # pip specs in Dockerfile.worker's main stack whose kernels land in the mega-cache. everything else
59
59
  # in that block is a base-layer dep (fp_base). fla is matched separately (it carries the git sha).
60
60
  _CACHE_PKGS = {"tilelang", "apache-tvm-ffi"}
61
+ _BAKED_ARCHES_NAME = "BAKED_PER_SM_ARCHES"
62
+ _BAKED_ARCH_PATTERN = re.compile(r"sm[0-9]+")
61
63
 
62
64
 
63
65
  def _search(pattern: str, text: str, what: str, *, flags: int = 0) -> str:
@@ -110,6 +112,62 @@ def _python_string_constant(text: str, name: str, what: str) -> str:
110
112
  return values[name]
111
113
 
112
114
 
115
+ def parse_baked_per_sm_arches(text: str, *, source: str = "_worker.py") -> list[str]:
116
+ """Parse the canonical baked-architecture frozenset without importing flash."""
117
+ tree = ast.parse(text, filename=source)
118
+ assignments = [
119
+ node
120
+ for node in tree.body
121
+ if (
122
+ isinstance(node, ast.Assign)
123
+ and any(isinstance(t, ast.Name) and t.id == _BAKED_ARCHES_NAME for t in node.targets)
124
+ )
125
+ or (
126
+ isinstance(node, ast.AnnAssign)
127
+ and isinstance(node.target, ast.Name)
128
+ and node.target.id == _BAKED_ARCHES_NAME
129
+ )
130
+ ]
131
+ context = f"kernel_fingerprint: {_BAKED_ARCHES_NAME} in {source}"
132
+ if len(assignments) != 1:
133
+ raise ValueError(
134
+ f"{context}: expected exactly one top-level assignment, found {len(assignments)}"
135
+ )
136
+
137
+ assignment = assignments[0]
138
+ if isinstance(assignment, ast.Assign) and (
139
+ len(assignment.targets) != 1 or not isinstance(assignment.targets[0], ast.Name)
140
+ ):
141
+ raise ValueError(f"{context} must use one named target")
142
+ value = assignment.value
143
+ if value is None:
144
+ raise ValueError(f"{context} must have a value")
145
+ if not (
146
+ isinstance(value, ast.Call)
147
+ and isinstance(value.func, ast.Name)
148
+ and value.func.id == "frozenset"
149
+ and len(value.args) == 1
150
+ and not value.keywords
151
+ and isinstance(value.args[0], ast.Set)
152
+ ):
153
+ raise ValueError(f"{context} must be frozenset({{...}}) of string literals")
154
+
155
+ arches: list[str] = []
156
+ for element in value.args[0].elts:
157
+ if not isinstance(element, ast.Constant) or not isinstance(element.value, str):
158
+ raise ValueError(f"{context} must contain strings")
159
+ if _BAKED_ARCH_PATTERN.fullmatch(element.value) is None:
160
+ raise ValueError(
161
+ f"{context} has invalid architecture {element.value!r}; expected sm followed by digits"
162
+ )
163
+ arches.append(element.value)
164
+ if not arches:
165
+ raise ValueError(f"{context} must not be empty")
166
+ if len(arches) != len(set(arches)):
167
+ raise ValueError(f"{context} must not contain duplicates")
168
+ return arches
169
+
170
+
113
171
  def _pip_stack_specs(dockerfile: str) -> list[str]:
114
172
  """The quoted specs from Dockerfile.worker's first `pip install` block (the pinned worker stack)."""
115
173
  specs: list[str] = []
@@ -257,6 +315,11 @@ def main(argv: list[str] | None = None) -> int:
257
315
  ap.add_argument(
258
316
  "--print-label-keys", action="store_true", help="print the OCI label keys + exit"
259
317
  )
318
+ ap.add_argument(
319
+ "--print-baked-arches",
320
+ action="store_true",
321
+ help="print BAKED_PER_SM_ARCHES from _worker.py + exit",
322
+ )
260
323
  args = ap.parse_args(argv)
261
324
 
262
325
  if args.print_label_keys:
@@ -265,8 +328,20 @@ def main(argv: list[str] | None = None) -> int:
265
328
  print(f"revision={LABEL_REVISION}")
266
329
  return 0
267
330
 
331
+ root = Path(args.root)
332
+ if args.print_baked_arches:
333
+ worker_source = root / "flash" / "providers" / "_worker.py"
334
+ try:
335
+ arches = parse_baked_per_sm_arches(
336
+ worker_source.read_text(encoding="utf-8"), source=str(worker_source)
337
+ )
338
+ except (OSError, SyntaxError, ValueError) as exc:
339
+ ap.error(str(exc))
340
+ print(" ".join(arches))
341
+ return 0
342
+
268
343
  fp_cache, fp_base, cache_inputs, base_inputs = fingerprints(
269
- Path(args.root), fa2_spec=args.fa2_spec, fa3_spec=args.fa3_spec
344
+ root, fa2_spec=args.fa2_spec, fa3_spec=args.fa3_spec
270
345
  )
271
346
  if args.explain:
272
347
  print(
@@ -1,7 +1,5 @@
1
1
  """Single switch between prod and dev channels; ``scripts/build_dev_dist.py`` rewrites CHANNEL to "dev"."""
2
2
 
3
- from __future__ import annotations
4
-
5
3
  CHANNEL = "dev"
6
4
 
7
5
  # Must stay in lockstep with [project.scripts] in pyproject.toml.
@@ -1,4 +1,4 @@
1
- """Small shared file-IO helpers for credential/manifest JSON under ``~/.flash``."""
1
+ """Small shared JSON file helpers for data under ``~/.flash``."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -9,7 +9,6 @@ import re
9
9
  import sys
10
10
  import threading
11
11
  import time
12
- import urllib.error
13
12
  import urllib.request
14
13
 
15
14
  from flash import __version__
@@ -27,7 +26,7 @@ _PYPI_JSON_URL = f"https://pypi.org/pypi/{PACKAGE_NAME}/json"
27
26
  CACHE_PATH = CONFIG_DIR / "update_check.json"
28
27
 
29
28
  _CHECK_INTERVAL_S = 24 * 60 * 60
30
- # join >= fetch timeout so the worker finishes writing before process exit kills it.
29
+ # keep the join budget above the fetch timeout to allow parsing and persistence before exit.
31
30
  _FETCH_TIMEOUT_S = 1.5
32
31
  _JOIN_TIMEOUT_S = 2.0
33
32
 
@@ -96,9 +95,7 @@ def _clean_version(value: object) -> str | None:
96
95
 
97
96
 
98
97
  def _read_cache() -> dict:
99
- # Coerce non-dict results (e.g. []) since _check_due runs before main()'s error handling.
100
- cache = read_json_or_empty(CACHE_PATH)
101
- return cache if isinstance(cache, dict) else {}
98
+ return read_json_or_empty(CACHE_PATH)
102
99
 
103
100
 
104
101
  def _check_due(now: float) -> bool:
@@ -122,7 +119,7 @@ def _fetch_latest_version(timeout: float = _FETCH_TIMEOUT_S) -> str | None:
122
119
  try:
123
120
  with urllib.request.urlopen(req, timeout=timeout) as resp:
124
121
  payload = json.loads(resp.read())
125
- except (urllib.error.URLError, OSError, ValueError, TimeoutError) as exc:
122
+ except (OSError, ValueError) as exc:
126
123
  logger.debug("update check: PyPI lookup failed: %s", exc)
127
124
  return None
128
125
  info = payload.get("info") if isinstance(payload, dict) else None
@@ -152,23 +149,16 @@ def _refresh_cache() -> None:
152
149
  logger.debug("update check: refresh failed: %s", exc)
153
150
 
154
151
 
155
- def _supports_color() -> bool:
156
- return not os.environ.get("NO_COLOR")
157
-
158
-
159
- def _red(text: str) -> str:
160
- return f"\033[31m{text}\033[0m" if _supports_color() else text
161
-
162
-
163
152
  def _build_notice() -> str | None:
164
153
  """Build the upgrade notice from the cached PyPI version, or ``None`` if up to date."""
165
154
  latest = _clean_version(_read_cache().get("pypi_version"))
166
155
  if not latest or _is_prerelease(latest) or not _is_newer(latest, __version__):
167
156
  return None
168
- return _red(
157
+ notice = (
169
158
  f"A new release of {PACKAGE_NAME} is available: {__version__} -> {latest}\n"
170
159
  f"Update with `{UPGRADE_COMMAND}`."
171
160
  )
161
+ return f"\033[31m{notice}\033[0m" if not os.environ.get("NO_COLOR") else notice
172
162
 
173
163
 
174
164
  def maybe_start_update_check() -> threading.Thread | None:
@@ -1,7 +1,5 @@
1
1
  """Shared adapter artifact filenames used by training and control-plane code."""
2
2
 
3
- from __future__ import annotations
4
-
5
3
  # The PEFT adapter weights file a deployable adapter must carry. Modern saves use safetensors,
6
4
  # but older PEFT/default settings may emit adapter_model.bin.
7
5
  ADAPTER_WEIGHT_FILES = ("adapter_model.safetensors", "adapter_model.bin")
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import math
6
- from dataclasses import asdict, dataclass
6
+ from dataclasses import asdict, dataclass, replace
7
7
  from typing import Any
8
8
 
9
9
  ALGORITHMS = ("sft", "grpo", "opd")
@@ -78,7 +78,7 @@ class ModelInfo:
78
78
  recommended_gpu: str = DEFAULT_GPU
79
79
  # 0 => GRPO uses min_vram_gb like SFT; set when colocated vLLM rollout needs a bigger card.
80
80
  grpo_min_vram_gb: int = 0
81
- # 0 => SFT sizes from param-based estimate; set only when a model must not down-route to the cheapest card.
81
+ # 0 => non-grpo sizing uses the param-based estimate; set when a model must not down-route to the cheapest card.
82
82
  sft_min_vram_gb: int = 0
83
83
  # vLLM sleep mode (offload the colocate rollout engine between GRPO steps) is NON-FUNCTIONAL for
84
84
  # this model: the wake/reload HANGS the rollout (a ~70 GB weight reallocation can't be placed in
@@ -124,9 +124,9 @@ class ModelInfo:
124
124
 
125
125
  def to_dict(self) -> dict[str, Any]:
126
126
  data = asdict(self)
127
- serving = data.get("serving")
127
+ serving = data["serving"]
128
128
  if serving is None:
129
- data.pop("serving", None)
129
+ del data["serving"]
130
130
  else:
131
131
  for key in (
132
132
  "serve_model_id",
@@ -162,7 +162,7 @@ MODELS: dict[str, ModelInfo] = {
162
162
  params="1.2B dense (Llama arch)",
163
163
  params_b=1.2,
164
164
  vocab_size=130_560,
165
- algos=("sft", "grpo", "opd"),
165
+ algos=ALGORITHMS,
166
166
  min_vram_gb=12,
167
167
  recommended_gpu="RTX 4090",
168
168
  serving=ServingCapacity(
@@ -181,7 +181,7 @@ MODELS: dict[str, ModelInfo] = {
181
181
  params="0.9B (text-only fine-tune)",
182
182
  params_b=0.9,
183
183
  vocab_size=248_320,
184
- algos=("sft", "grpo", "opd"),
184
+ algos=ALGORITHMS,
185
185
  min_vram_gb=12,
186
186
  recommended_gpu="RTX 4090",
187
187
  serving=ServingCapacity(
@@ -200,7 +200,7 @@ MODELS: dict[str, ModelInfo] = {
200
200
  params="2.3B (text-only fine-tune)",
201
201
  params_b=2.3,
202
202
  vocab_size=248_320,
203
- algos=("sft", "grpo", "opd"),
203
+ algos=ALGORITHMS,
204
204
  min_vram_gb=16,
205
205
  recommended_gpu="RTX 4090",
206
206
  serving=ServingCapacity(
@@ -218,7 +218,7 @@ MODELS: dict[str, ModelInfo] = {
218
218
  params="4.7B (text-only fine-tune)",
219
219
  params_b=4.7,
220
220
  vocab_size=248_320,
221
- algos=("sft", "grpo", "opd"),
221
+ algos=ALGORITHMS,
222
222
  min_vram_gb=32,
223
223
  recommended_gpu="RTX 5090",
224
224
  serving=ServingCapacity(
@@ -240,7 +240,7 @@ MODELS: dict[str, ModelInfo] = {
240
240
  params="9.7B (text-only fine-tune)",
241
241
  params_b=9.7,
242
242
  vocab_size=248_320,
243
- algos=("sft", "grpo", "opd"),
243
+ algos=ALGORITHMS,
244
244
  min_vram_gb=48,
245
245
  # NOT QLoRA: peft bnb merge during GRPO rollout diverges trainer precision -> TRL ratio collapses to 0.
246
246
  grpo_min_vram_gb=80,
@@ -272,7 +272,7 @@ MODELS: dict[str, ModelInfo] = {
272
272
  num_layers=40,
273
273
  hidden_size=2048,
274
274
  vocab_size=248_320,
275
- algos=("sft", "grpo", "opd"),
275
+ algos=ALGORITHMS,
276
276
  min_vram_gb=141,
277
277
  # Floor to 100 GB so SFT lands on H200, not the thin-margin consumer Blackwell or 80 GB H100.
278
278
  sft_min_vram_gb=100,
@@ -328,19 +328,20 @@ def get_model(model_id: str) -> ModelInfo:
328
328
  ) from exc
329
329
 
330
330
 
331
+ def _model_info_for_serving(model: str | ModelInfo | None) -> ModelInfo | None:
332
+ if isinstance(model, ModelInfo):
333
+ return model
334
+ if isinstance(model, str) and model.strip():
335
+ return MODELS.get(model.strip())
336
+ return None
337
+
338
+
331
339
  def serving_lora_rank_cap(model: str | ModelInfo | None) -> int | None:
332
- """Return the model's serving LoRA rank cap, or None when Flash has no local cap.
340
+ """Return the model-specific serving LoRA rank cap.
333
341
 
334
- Serving capacity is model-specific: small serving models currently allow rank 64, while larger
335
- serving paths currently allow rank 32. Unknown/open-policy models intentionally return None instead
336
- of inheriting a global fallback.
342
+ Unknown and open-policy models return None.
337
343
  """
338
- if isinstance(model, ModelInfo):
339
- info = model
340
- elif isinstance(model, str) and model.strip():
341
- info = MODELS.get(model.strip())
342
- else:
343
- info = None
344
+ info = _model_info_for_serving(model)
344
345
  if info is None or info.serving is None:
345
346
  return None
346
347
  return int(info.serving.max_lora_rank)
@@ -355,12 +356,7 @@ def serving_context_cap(model: str | ModelInfo | None) -> int | None:
355
356
  ``flash.lora_rank.preflight_train_context_within_serving``). Resolution mirrors
356
357
  ``serving_lora_rank_cap``: unknown/open-policy models return None rather than a global fallback.
357
358
  """
358
- if isinstance(model, ModelInfo):
359
- info = model
360
- elif isinstance(model, str) and model.strip():
361
- info = MODELS.get(model.strip())
362
- else:
363
- info = None
359
+ info = _model_info_for_serving(model)
364
360
  if info is None or info.serving is None:
365
361
  return None
366
362
  return int(info.serving.max_model_len)
@@ -372,26 +368,66 @@ def vocab_size_for(model_id: str) -> int:
372
368
  return info.vocab_size if info is not None else _DEFAULT_VOCAB_SIZE
373
369
 
374
370
 
371
+ def resolve_vocab_size(model_id: str, revision: str = "") -> int:
372
+ """vocab_size for a model, revision-aware when a commit is pinned (mirrors resolve_params_b).
373
+
374
+ catalog vocab by default; for a pinned revision, the hf config vocab validated against the
375
+ catalog (fail-closed, same as the vram path).
376
+ """
377
+ info = MODELS.get(model_id)
378
+ if revision:
379
+ from flash.engine.vram import _validated_revision_geometry, fetch_hf_model_geometry
380
+
381
+ if info is not None:
382
+ _params_b, vocab = _validated_revision_geometry(model_id, revision, info)
383
+ return int(vocab or info.vocab_size)
384
+ _p, vocab, _h, _l = fetch_hf_model_geometry(model_id, revision, strict=True)
385
+ if vocab:
386
+ return int(vocab)
387
+ return vocab_size_for(model_id)
388
+
389
+
375
390
  def resolve_model(
376
391
  model_id: str,
377
392
  algorithm: str,
378
393
  policy: str = "catalog",
379
394
  gpu: str | None = None,
395
+ model_revision: str = "",
380
396
  ) -> ModelInfo:
381
397
  """Resolve a model under the configured policy; "allow" accepts any HF model."""
382
398
  algo = normalize_algorithm(algorithm)
383
399
  if model_id in MODELS:
384
- return validate_model_for_algorithm(model_id, algo)
400
+ info = validate_model_for_algorithm(model_id, algo)
401
+ if model_revision:
402
+ from flash.engine.vram import _validated_revision_geometry
403
+
404
+ params_b, vocab_size = _validated_revision_geometry(model_id, model_revision, info)
405
+ info = replace(
406
+ info,
407
+ params_b=params_b,
408
+ params=f"{params_b:.1f}B",
409
+ vocab_size=vocab_size,
410
+ min_disk_gb=max(info.min_disk_gb, int(params_b * 2) + 64),
411
+ )
412
+ return info
385
413
  if policy != "allow":
386
414
  return get_model(model_id)
387
- return _resolve_open_model(model_id, algo, gpu)
415
+ return _resolve_open_model(model_id, algo, gpu, model_revision=model_revision)
388
416
 
389
417
 
390
- def _resolve_open_model(model_id: str, algo: str, gpu: str | None) -> ModelInfo:
418
+ def _resolve_open_model(
419
+ model_id: str, algo: str, gpu: str | None, *, model_revision: str = ""
420
+ ) -> ModelInfo:
391
421
  """Synthesize a ModelInfo for the open-model "allow" policy via a coarse HF VRAM-fit estimate."""
392
422
  from flash.engine.vram import check_fit
393
423
 
394
- est = check_fit(model_id, algo, gpu or DEFAULT_GPU)
424
+ resolved_gpu = gpu or DEFAULT_GPU
425
+ est = check_fit(
426
+ model_id,
427
+ algo,
428
+ resolved_gpu,
429
+ model_revision=model_revision,
430
+ )
395
431
  if est.verdict == "too_big":
396
432
  raise ValueError(
397
433
  f"{model_id} does not fit the requested GPU: {est.describe()}. "
@@ -399,19 +435,20 @@ def _resolve_open_model(model_id: str, algo: str, gpu: str | None) -> ModelInfo:
399
435
  )
400
436
  if est.verdict in ("tight", "unknown"):
401
437
  print(f"warning: open-model policy: {est.describe()}")
402
- params = f"{est.params_b:.1f}B" if est.params_b else "unknown size"
403
- min_disk = int(est.params_b * 2) + 64 if est.params_b else 0
438
+ params_b = est.params_b or 0.0
439
+ params = f"{params_b:.1f}B" if params_b else "unknown size"
440
+ min_disk = int(params_b * 2) + 64 if params_b else 0
404
441
  return ModelInfo(
405
442
  id=model_id,
406
443
  display_name=model_id,
407
444
  params=params,
408
445
  # Carry the estimated/HF param count straight through (0.0 when size is unknown) so downstream
409
446
  # sizing reads ``params_b`` directly — no re-parsing the display string.
410
- params_b=est.params_b or 0.0,
447
+ params_b=params_b,
411
448
  algos=ALGORITHMS,
412
449
  min_vram_gb=math.ceil(est.est_gb) if est.est_gb else 24,
413
450
  min_disk_gb=min_disk,
414
- recommended_gpu=gpu or DEFAULT_GPU,
451
+ recommended_gpu=resolved_gpu,
415
452
  thinking="unknown",
416
453
  notes="unlisted model accepted via the open-model policy (not curated/validated)",
417
454
  )
@@ -11,20 +11,14 @@ from typing import NoReturn
11
11
 
12
12
  from flash import __version__
13
13
  from flash._channel import CLI_NAME
14
- from flash._logging import configure_logging, get_logger
14
+ from flash._logging import configure_logging
15
15
  from flash._update_check import emit_update_notice, maybe_start_update_check
16
16
  from flash.cli import render
17
17
 
18
- # Command handlers + the patched client surface live in submodules; re-export them so
19
- # `flash.cli` stays the single public import surface (and so monkeypatching
20
- # `flash.cli.commands` reaches the bare globals the handlers read).
18
+ # package-level command imports remain available through flash.cli.
21
19
  from flash.cli.commands import ( # noqa: F401
22
20
  _CLI_DONE_STATES,
23
- _OK_STATES,
24
- _STARTER_ENV_PY,
25
21
  _USER_ERRORS,
26
- _follow_run,
27
- _poll_logs,
28
22
  client_from_config,
29
23
  cmd_cancel,
30
24
  cmd_chat,
@@ -32,7 +26,6 @@ from flash.cli.commands import ( # noqa: F401
32
26
  cmd_deploy,
33
27
  cmd_deployments,
34
28
  cmd_env_list,
35
- cmd_env_setup,
36
29
  cmd_export,
37
30
  cmd_gpus,
38
31
  cmd_log,
@@ -46,10 +39,9 @@ from flash.cli.commands import ( # noqa: F401
46
39
  cmd_whoami,
47
40
  verify_freesolo_key,
48
41
  )
42
+ from flash.cli.env_setup import cmd_env_setup
49
43
  from flash.cli.envpush import cmd_env_delete, cmd_env_pull, cmd_env_push
50
44
 
51
- logger = get_logger("flash.cli")
52
-
53
45
  # Themed `flash --help` catalog. Groups are ordered along the training workflow; each row's
54
46
  # summary is the short one-liner the themed grid shows (the verbose per-command text stays on
55
47
  # every subparser's own `help=` / `<cmd> --help`). test_cli_help.py asserts these rows stay in
@@ -392,12 +384,6 @@ def _build_parser() -> argparse.ArgumentParser:
392
384
  help="run id for the final adapter, or RUN_ID/step-N for a saved checkpoint",
393
385
  )
394
386
  deploy.add_argument("--dry-run", action="store_true")
395
- deploy.add_argument(
396
- "--no-verify",
397
- action="store_true",
398
- help="skip the server-side post-deploy smoke generation (registration alone does NOT "
399
- "guarantee the adapter serves; only ready deployments should be scored by evals)",
400
- )
401
387
  deploy.set_defaults(func=cmd_deploy)
402
388
 
403
389
  undeploy = sub.add_parser("undeploy", help="tear down a run's serving endpoint")
@@ -430,6 +416,11 @@ def _build_parser() -> argparse.ArgumentParser:
430
416
  export.set_defaults(func=cmd_export)
431
417
 
432
418
  deployments = sub.add_parser("deployments", help="list active serving deployments")
419
+ deployments.add_argument(
420
+ "--json",
421
+ action="store_true",
422
+ help="print machine-readable deployment records",
423
+ )
433
424
  deployments.set_defaults(func=cmd_deployments)
434
425
 
435
426
  chat = sub.add_parser("chat", help="chat with a deployed adapter")