freesolo-flash-dev 1.0.83__tar.gz → 1.0.85__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 (402) hide show
  1. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/PKG-INFO +1 -1
  2. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/catalog.py +4 -2
  3. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/__init__.py +4 -0
  4. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/adapter.py +31 -3
  5. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/backend_common.py +67 -12
  6. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_train.py +9 -0
  7. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/lifecycle.py +16 -7
  8. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rl_train.py +45 -3
  9. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/sft_train.py +7 -0
  10. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/pyproject.toml +2 -2
  11. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_allocator.py +46 -10
  12. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_backend_common.py +137 -1
  13. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_gpus_flag.py +7 -2
  14. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_analytical.py +14 -10
  15. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_gpus.py +41 -0
  16. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_resident_sizing.py +28 -17
  17. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd.py +8 -3
  18. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd_train.py +18 -0
  19. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_rl_train.py +160 -2
  20. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_api.py +4 -4
  21. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_gc_off.py +28 -5
  22. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_train.py +17 -0
  23. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vram_architecture.py +12 -5
  24. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_stack.py +32 -2
  25. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/uv.lock +1 -1
  26. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.dockerignore +0 -0
  27. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.env.example +0 -0
  28. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  29. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  30. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  31. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  32. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/dependabot.yml +0 -0
  33. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/auto-rebake.yml +0 -0
  34. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/bake-kernel-cache.yml +0 -0
  35. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/ci.yml +0 -0
  36. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/main-source-guard.yml +0 -0
  37. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/notify-tests-repo.yml +0 -0
  38. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/publish-dev.yml +0 -0
  39. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/publish-image.yml +0 -0
  40. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/publish.yml +0 -0
  41. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/version-parity.yml +0 -0
  42. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.github/workflows/worker-image.yml +0 -0
  43. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/.gitignore +0 -0
  44. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/CODE_OF_CONDUCT.md +0 -0
  45. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/CONTRIBUTING.md +0 -0
  46. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/Dockerfile +0 -0
  47. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/Dockerfile.worker +0 -0
  48. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/LICENSE +0 -0
  49. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/NOTICE +0 -0
  50. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/README.md +0 -0
  51. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/SECURITY.md +0 -0
  52. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/SELF_HOSTING.md +0 -0
  53. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/build/kernel_cache/.gitignore +0 -0
  54. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/build/kernel_cache/.keep +0 -0
  55. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/Dockerfile.kernelcache +0 -0
  56. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/Dockerfile.kernelcache.relayer +0 -0
  57. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/bake_kernel_cache.py +0 -0
  58. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/bake_pod_entry.py +0 -0
  59. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/kernel_fingerprint.py +0 -0
  60. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/docker/make_rp_handler.py +0 -0
  61. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/__init__.py +0 -0
  62. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_channel.py +0 -0
  63. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_fileio.py +0 -0
  64. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_logging.py +0 -0
  65. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/_update_check.py +0 -0
  66. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/adapter_artifacts.py +0 -0
  67. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/TRAINING.md +0 -0
  68. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/__init__.py +0 -0
  69. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/__main__.py +0 -0
  70. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/_tty.py +0 -0
  71. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/commands.py +0 -0
  72. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/env_eval.py +0 -0
  73. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/env_setup.py +0 -0
  74. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/env_test.py +0 -0
  75. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/envpush.py +0 -0
  76. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/render.py +0 -0
  77. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/traces.py +0 -0
  78. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cli/training_doc.py +0 -0
  79. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/__init__.py +0 -0
  80. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/config.py +0 -0
  81. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/http.py +0 -0
  82. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/runtime_secrets.py +0 -0
  83. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/client/specs.py +0 -0
  84. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/__init__.py +0 -0
  85. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/analytical.py +0 -0
  86. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/facts.py +0 -0
  87. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/spec.py +0 -0
  88. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/cost/types.py +0 -0
  89. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/diagnostics.py +0 -0
  90. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/__init__.py +0 -0
  91. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/accounting.py +0 -0
  92. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/multiturn_reward_scoring.py +0 -0
  93. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/recipe.py +0 -0
  94. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/reward_profile.py +0 -0
  95. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/steps.py +0 -0
  96. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/structured_outputs.py +0 -0
  97. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/vram.py +0 -0
  98. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/__main__.py +0 -0
  99. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/_pkg.py +0 -0
  100. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/decoding.py +0 -0
  101. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/finalize.py +0 -0
  102. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/grpo.py +0 -0
  103. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/grpo_multiturn.py +0 -0
  104. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/grpo_plugin.py +0 -0
  105. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/heartbeat.py +0 -0
  106. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/hf.py +0 -0
  107. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/kernel_warmup.py +0 -0
  108. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/lora.py +0 -0
  109. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/multiturn_glue.py +0 -0
  110. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd.py +0 -0
  111. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_gkd.py +0 -0
  112. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_multiturn.py +0 -0
  113. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_plugin.py +0 -0
  114. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/opd_structured.py +0 -0
  115. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/packing.py +0 -0
  116. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/__init__.py +0 -0
  117. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/attn.py +0 -0
  118. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/diagnostics.py +0 -0
  119. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/liger.py +0 -0
  120. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/loraplus.py +0 -0
  121. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/perf/memory.py +0 -0
  122. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rl.py +0 -0
  123. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rng.py +0 -0
  124. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/rollout_samples.py +0 -0
  125. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/sft.py +0 -0
  126. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/teacher.py +0 -0
  127. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/teacher_encoding.py +0 -0
  128. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/tokenizer_align.py +0 -0
  129. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker/wandb_log.py +0 -0
  130. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/engine/worker_entrypoint.py +0 -0
  131. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/__init__.py +0 -0
  132. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/adapter.py +0 -0
  133. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/archive.py +0 -0
  134. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/archive_policy.py +0 -0
  135. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/base.py +0 -0
  136. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/evaluations.py +0 -0
  137. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/loader.py +0 -0
  138. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/pull.py +0 -0
  139. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/envs/registry.py +0 -0
  140. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/lora_rank.py +0 -0
  141. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/multimodal.py +0 -0
  142. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/opd_limits.py +0 -0
  143. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/opd_retry_contract.py +0 -0
  144. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/opd_validation.py +0 -0
  145. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/__init__.py +0 -0
  146. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_auth.py +0 -0
  147. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_deadline.py +0 -0
  148. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_hf_artifacts.py +0 -0
  149. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_hf_retry.py +0 -0
  150. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_http.py +0 -0
  151. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance.py +0 -0
  152. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance_bootstrap.py +0 -0
  153. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance_poll.py +0 -0
  154. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_instance_provider.py +0 -0
  155. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_poll.py +0 -0
  156. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/_worker.py +0 -0
  157. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/allocator.py +0 -0
  158. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/base.py +0 -0
  159. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/__init__.py +0 -0
  160. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/api.py +0 -0
  161. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/auth.py +0 -0
  162. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/gpus.py +0 -0
  163. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
  164. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/jobs/builders.py +0 -0
  165. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/preflight.py +0 -0
  166. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/lambdalabs/pricing.py +0 -0
  167. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/preflight.py +0 -0
  168. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/realized.py +0 -0
  169. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/__init__.py +0 -0
  170. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/api.py +0 -0
  171. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/auth.py +0 -0
  172. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/cost.py +0 -0
  173. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/gpus.py +0 -0
  174. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/jobs.py +0 -0
  175. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/keys.py +0 -0
  176. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/preflight.py +0 -0
  177. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/pricing.py +0 -0
  178. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/slots.py +0 -0
  179. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/train/__init__.py +0 -0
  180. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/runpod/train/endpoints.py +0 -0
  181. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/__init__.py +0 -0
  182. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/api.py +0 -0
  183. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/auth.py +0 -0
  184. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/jobs/__init__.py +0 -0
  185. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/jobs/builders.py +0 -0
  186. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/preflight.py +0 -0
  187. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/vast/pricing.py +0 -0
  188. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/providers/weight_cache_preload.py +0 -0
  189. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/py.typed +0 -0
  190. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/__init__.py +0 -0
  191. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/checkpoints.py +0 -0
  192. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/deploy.py +0 -0
  193. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/lifecycle.py +0 -0
  194. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/runner/verified_revisions.py +0 -0
  195. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/schema/__init__.py +0 -0
  196. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/schema/fields.py +0 -0
  197. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/__init__.py +0 -0
  198. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/deploy.py +0 -0
  199. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/export.py +0 -0
  200. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/preflight.py +0 -0
  201. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/pricing.py +0 -0
  202. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/serve/urls.py +0 -0
  203. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/__init__.py +0 -0
  204. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/__main__.py +0 -0
  205. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_deps.py +0 -0
  206. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_internal_client.py +0 -0
  207. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_locks.py +0 -0
  208. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/_runtime.py +0 -0
  209. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/app.py +0 -0
  210. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/auth.py +0 -0
  211. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/billing.py +0 -0
  212. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/billing_retry.py +0 -0
  213. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/checkpoints.py +0 -0
  214. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/db.py +0 -0
  215. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/environment_registry.py +0 -0
  216. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/envs.py +0 -0
  217. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/projects.py +0 -0
  218. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/reconcile.py +0 -0
  219. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/repo_cleanup.py +0 -0
  220. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/__init__.py +0 -0
  221. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/envs.py +0 -0
  222. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/meta.py +0 -0
  223. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/runs.py +0 -0
  224. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/serving.py +0 -0
  225. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/routes/teacher.py +0 -0
  226. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/run_registry.py +0 -0
  227. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/server/teacher_broker.py +0 -0
  228. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/spec.py +0 -0
  229. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/flash/thinking.py +0 -0
  230. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/infisical-entrypoint.sh +0 -0
  231. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/scripts/build_dev_dist.py +0 -0
  232. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/scripts/scrub_history.sh +0 -0
  233. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/__init__.py +0 -0
  234. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/__init__.py +0 -0
  235. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/runner.py +0 -0
  236. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/specs.py +0 -0
  237. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/_helpers/vast.py +0 -0
  238. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/conftest.py +0 -0
  239. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/fixtures/math_eval.jsonl +0 -0
  240. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/fixtures/math_train.jsonl +0 -0
  241. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/__init__.py +0 -0
  242. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/conftest.py +0 -0
  243. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/test_lambda_live.py +0 -0
  244. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/test_runpod_live.py +0 -0
  245. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/live/test_vast_live.py +0 -0
  246. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_accounting_coverage.py +0 -0
  247. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_agent_flash_cli_contract.py +0 -0
  248. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_algorithms.py +0 -0
  249. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_async_uploads.py +0 -0
  250. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_backend_jobspec_contract.py +0 -0
  251. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_base_model_provenance.py +0 -0
  252. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_billing_retry.py +0 -0
  253. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cancel_remote.py +0 -0
  254. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_catalog_consistency.py +0 -0
  255. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_charge_pricing.py +0 -0
  256. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_checkpoints.py +0 -0
  257. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_commands.py +0 -0
  258. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_commands_coverage.py +0 -0
  259. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_credential_shadowing.py +0 -0
  260. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_errors.py +0 -0
  261. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_estimate.py +0 -0
  262. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_help.py +0 -0
  263. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_main_coverage.py +0 -0
  264. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_managed.py +0 -0
  265. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_render_coverage.py +0 -0
  266. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_render_theme.py +0 -0
  267. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_traces.py +0 -0
  268. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cli_wandb_warning.py +0 -0
  269. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_client.py +0 -0
  270. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_client_server_integration.py +0 -0
  271. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_client_stream_reads.py +0 -0
  272. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_config_overrides.py +0 -0
  273. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_controlled_experiment_repairs.py +0 -0
  274. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_equation.py +0 -0
  275. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_estimate.py +0 -0
  276. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_hardware.py +0 -0
  277. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_models.py +0 -0
  278. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_cost_rewards.py +0 -0
  279. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_deploy_latency.py +0 -0
  280. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_dev_channel.py +0 -0
  281. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_disk_gb.py +0 -0
  282. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_endpoint_name.py +0 -0
  283. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_cache_evict.py +0 -0
  284. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_delete.py +0 -0
  285. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_download.py +0 -0
  286. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_download_api.py +0 -0
  287. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_evaluations.py +0 -0
  288. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_no_install.py +0 -0
  289. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_publish.py +0 -0
  290. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull.py +0 -0
  291. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull_coverage.py +0 -0
  292. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull_loader_coverage.py +0 -0
  293. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_pull_managed_control_plane.py +0 -0
  294. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_push.py +0 -0
  295. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_rate_limit_resolve.py +0 -0
  296. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_ref_pinning.py +0 -0
  297. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_env_test.py +0 -0
  298. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_envs_coverage.py +0 -0
  299. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_export.py +0 -0
  300. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_flash_mvp.py +0 -0
  301. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_flash_worker.py +0 -0
  302. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_flashinfer_cache_dirs.py +0 -0
  303. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_github_urlopen_retry.py +0 -0
  304. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_gpu_type_single_field.py +0 -0
  305. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_mask_aware.py +0 -0
  306. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_params.py +0 -0
  307. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_grpo_reward_batching.py +0 -0
  308. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_health_liveness.py +0 -0
  309. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_hf_retry.py +0 -0
  310. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_idle_endpoint_reaper.py +0 -0
  311. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_instance_bootstrap_coverage.py +0 -0
  312. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_internal_client.py +0 -0
  313. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_jobs.py +0 -0
  314. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_kernel_cache.py +0 -0
  315. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_kernel_fingerprint.py +0 -0
  316. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_kv_util.py +0 -0
  317. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lambda_api_coverage.py +0 -0
  318. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lambda_runner.py +0 -0
  319. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_logging.py +0 -0
  320. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_login_perms.py +0 -0
  321. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lora_rank_coverage.py +0 -0
  322. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_lora_rank_preflight.py +0 -0
  323. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_managed_config_fields.py +0 -0
  324. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_managed_hf_repo.py +0 -0
  325. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_metrics_schema_agent_contract.py +0 -0
  326. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_mig_guard.py +0 -0
  327. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_multi_gpu_gate.py +0 -0
  328. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_multimodal_input_grads.py +0 -0
  329. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_multimodal_training.py +0 -0
  330. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_named_reward_metrics.py +0 -0
  331. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_oom_escalate_gpu.py +0 -0
  332. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd_limits.py +0 -0
  333. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_opd_resume_safety.py +0 -0
  334. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_open_model_policy.py +0 -0
  335. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_orchestrator_flash.py +0 -0
  336. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_packing.py +0 -0
  337. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_packing_coverage.py +0 -0
  338. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_parasail_teacher.py +0 -0
  339. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_poll_helpers.py +0 -0
  340. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_preflight.py +0 -0
  341. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_projects.py +0 -0
  342. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_provider_preflight_coverage.py +0 -0
  343. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_provider_routing.py +0 -0
  344. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_provider_teardown_robustness.py +0 -0
  345. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_providers_symmetry.py +0 -0
  346. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_realized_cost.py +0 -0
  347. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_repo_cleanup.py +0 -0
  348. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_resolve_params_b.py +0 -0
  349. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_resume_on_retry.py +0 -0
  350. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_reward_profile.py +0 -0
  351. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_rollout_samples.py +0 -0
  352. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runmgmt.py +0 -0
  353. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_api_delete.py +0 -0
  354. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_key_fingerprint.py +0 -0
  355. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_key_waterfall.py +0 -0
  356. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_runpod_slots.py +0 -0
  357. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serve.py +0 -0
  358. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serve_reasoning_content.py +0 -0
  359. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_app_coverage.py +0 -0
  360. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_auth_singleflight.py +0 -0
  361. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_billing.py +0 -0
  362. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_checkpoints_coverage.py +0 -0
  363. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_db.py +0 -0
  364. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_envs_coverage.py +0 -0
  365. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_locks_coverage.py +0 -0
  366. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_server_standalone.py +0 -0
  367. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_context_preflight.py +0 -0
  368. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_contract.py +0 -0
  369. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_pricing_coverage.py +0 -0
  370. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_serving_schema_coverage.py +0 -0
  371. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_chunked_nll.py +0 -0
  372. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_example_selection.py +0 -0
  373. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_sft_max_context.py +0 -0
  374. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_spec_and_validation.py +0 -0
  375. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_step_metrics.py +0 -0
  376. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_structured_outputs.py +0 -0
  377. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_teacher_broker.py +0 -0
  378. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_thinking_config.py +0 -0
  379. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_train_context_preflight.py +0 -0
  380. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_training_controls.py +0 -0
  381. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_update_check.py +0 -0
  382. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_api.py +0 -0
  383. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_api_coverage.py +0 -0
  384. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_offers.py +0 -0
  385. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_provider_coverage.py +0 -0
  386. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vast_runner.py +0 -0
  387. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_verified_revisions.py +0 -0
  388. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_verifiers.py +0 -0
  389. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_version.py +0 -0
  390. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  391. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_wandb_link.py +0 -0
  392. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_wandb_log_coverage.py +0 -0
  393. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_wandb_naming.py +0 -0
  394. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_warmstart_adapter_download.py +0 -0
  395. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_warmstart_cross_repo.py +0 -0
  396. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_warmstart_error_attribution.py +0 -0
  397. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_weight_cache.py +0 -0
  398. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_dryrun.py +0 -0
  399. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_hardexit.py +0 -0
  400. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_image.py +0 -0
  401. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_init_heartbeat.py +0 -0
  402. {freesolo_flash_dev-1.0.83 → freesolo_flash_dev-1.0.85}/tests/test_worker_thinking.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freesolo-flash-dev
3
- Version: 1.0.83
3
+ Version: 1.0.85
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
@@ -466,16 +466,18 @@ MODELS: dict[str, ModelInfo] = {
466
466
  # vllm 0.19.1 derives the 1,097,728-byte gdn state page as 1072 fp8 attention
467
467
  # tokens after the 16-token backend alignment.
468
468
  mamba_block_size=1072,
469
- # peft targets shared-expert linears on every layer. fused routed-expert tensors are not
470
- # nn.linear modules and are not adapter targets in the loaded model.
469
+ # peft targets ordinary linears plus both fused routed-expert tensors on every layer.
470
+ # each routed tensor has 256 expert slices, all using the adapter's uniform serving rank.
471
471
  lora_target_shapes=(
472
472
  (512, 2048, 40),
473
+ (512, 2048, 10_240),
473
474
  (1152, 1152, 27),
474
475
  (1152, 3456, 27),
475
476
  (1152, 4304, 27),
476
477
  (2048, 1, 40),
477
478
  (2048, 32, 60),
478
479
  (2048, 512, 100),
480
+ (2048, 1024, 10_240),
479
481
  (2048, 4096, 30),
480
482
  (2048, 8192, 40),
481
483
  (4096, 2048, 40),
@@ -22,10 +22,12 @@ from flash.engine.worker.adapter import (
22
22
  _download_adapter,
23
23
  _init_adapter_model,
24
24
  _resolve_adapter_ref,
25
+ lora_target_parameters,
25
26
  make_lora,
26
27
  prepare_fresh_lora_base,
27
28
  require_vllm_for_rollout_func,
28
29
  stamp_adapter_provenance,
30
+ validate_lora_target_parameters,
29
31
  )
30
32
  from flash.engine.worker.backend_common import collect_ray_failure_logs
31
33
  from flash.engine.worker.decoding import (
@@ -531,6 +533,7 @@ __all__ = [
531
533
  "liger_on",
532
534
  "load_mega_cache",
533
535
  "load_tokenizer",
536
+ "lora_target_parameters",
534
537
  "loraplus_optimizer_cls",
535
538
  "main",
536
539
  "make_checkpoint_upload_callback",
@@ -560,6 +563,7 @@ __all__ = [
560
563
  "thinking_text",
561
564
  "upload_debug_jsonl",
562
565
  "upload_resume_checkpoint",
566
+ "validate_lora_target_parameters",
563
567
  "wait_for_gpu",
564
568
  "wandb_finish",
565
569
  "wandb_report_to",
@@ -27,11 +27,35 @@ from flash.engine.worker.perf import optimal_attn_impl
27
27
 
28
28
  _ADAPTER_DOWNLOAD_RETRIES = 4
29
29
  _ADAPTER_DOWNLOAD_BACKOFF_S = 5.0
30
+ _QWEN35_EXPERT_TARGET_PARAMETERS = (
31
+ "mlp.experts.gate_up_proj",
32
+ "mlp.experts.down_proj",
33
+ )
34
+
35
+
36
+ def lora_target_parameters(model_id: str | None) -> list[str] | None:
37
+ """return direct parameter targets required by the model's fused expert layout."""
38
+ if model_id == "Qwen/Qwen3.6-35B-A3B":
39
+ return list(_QWEN35_EXPERT_TARGET_PARAMETERS)
40
+ return None
41
+
42
+
43
+ def validate_lora_target_parameters(config: dict, model_id: str) -> None:
44
+ """fail closed when a warm-start adapter omits required fused expert parameters."""
45
+ required = set(lora_target_parameters(model_id) or ())
46
+ if not required:
47
+ return
48
+ actual = set(config.get("target_parameters") or ())
49
+ missing = sorted(required - actual)
50
+ if missing:
51
+ raise ValueError(
52
+ f"warm-start adapter for {model_id} omits required expert targets {missing}; "
53
+ "retrain the source adapter with the current Flash version"
54
+ )
30
55
 
31
56
 
32
57
  def make_lora(model_id: str | None = None):
33
- """Build LoRA config targeting all linear layers (VL models included: the vision tower /
34
- projector / MTP linears are adapted too; on examples without images they simply get no gradient)."""
58
+ """build the model's complete serve-compatible lora target set."""
35
59
  from peft import LoraConfig
36
60
 
37
61
  targets = "all-linear"
@@ -46,7 +70,9 @@ def make_lora(model_id: str | None = None):
46
70
  "task_type": "CAUSAL_LM",
47
71
  "revision": model_revision or None,
48
72
  }
49
- # PiSSA removed: it mutates the base, so its adapter corrupts serve + warm-start on the unmodified base.
73
+ if target_parameters := lora_target_parameters(model_id):
74
+ kwargs["target_parameters"] = target_parameters
75
+ # pissa removed: it mutates the base, so its adapter corrupts serve + warm-start on the unmodified base.
50
76
  kwargs["init_lora_weights"] = True
51
77
  print(
52
78
  "[lora] init_lora_weights=True (standard zero-B; PiSSA removed for serve/warm-start safety)"
@@ -160,6 +186,8 @@ def _init_adapter_model(model_id: str):
160
186
  "refusing to silently start from the base model. Verify the source run and access, "
161
187
  "or omit init_from_adapter to train a fresh LoRA."
162
188
  )
189
+ with open(os.path.join(adir, "adapter_config.json"), encoding="utf-8") as config_file:
190
+ validate_lora_target_parameters(json.load(config_file), model_id)
163
191
  print("[init-adapter] continuing the prepared source LoRA")
164
192
  _attn = optimal_attn_impl()
165
193
  attn_kw = {"attn_implementation": _attn} if _attn else {}
@@ -808,6 +808,10 @@ _CHILD_TAIL_LINE_CHARS = 300
808
808
  # how many retained lines ride along on a pre-first-step heartbeat. narrower than what is retained:
809
809
  # this payload is uploaded every tick, so it stays small enough not to bloat the snapshot.
810
810
  STALL_TAIL_LINES = 15
811
+ _RETRIABLE_VERL_CHILD_SIGNATURES = (
812
+ "cudaErrorDevicesUnavailable",
813
+ "CUDA-capable device(s) is/are busy or unavailable",
814
+ )
811
815
 
812
816
 
813
817
  class ChildOutputTail:
@@ -826,13 +830,34 @@ class ChildOutputTail:
826
830
  def __init__(self, limit: int = CHILD_TAIL_LINES) -> None:
827
831
  self._lines: collections.deque[str] = collections.deque(maxlen=limit)
828
832
  self._written = 0
833
+ self._retriable_infra_signature: str | None = None
834
+ self._cuda_oom_evidence: str | None = None
829
835
 
830
836
  def record(self, line: str) -> None:
837
+ if self._retriable_infra_signature is None:
838
+ self._retriable_infra_signature = next(
839
+ (signature for signature in _RETRIABLE_VERL_CHILD_SIGNATURES if signature in line),
840
+ None,
841
+ )
842
+ if self._cuda_oom_evidence is None:
843
+ from flash.engine.worker.perf.lifecycle import cuda_oom_message_evidence
844
+
845
+ self._cuda_oom_evidence = cuda_oom_message_evidence(line)
831
846
  text = line.rstrip("\n")
832
847
  if text:
833
848
  self._lines.append(text[:_CHILD_TAIL_LINE_CHARS])
834
849
  self._written += 1
835
850
 
851
+ @property
852
+ def retriable_infra_signature(self) -> str | None:
853
+ """the first stable retriable-infrastructure signature observed in child output."""
854
+ return self._retriable_infra_signature
855
+
856
+ @property
857
+ def cuda_oom_evidence(self) -> str | None:
858
+ """the first authoritative cuda oom message evidence observed in child output."""
859
+ return self._cuda_oom_evidence
860
+
836
861
  @property
837
862
  def written(self) -> int:
838
863
  """how many non-empty lines the child has produced, ever.
@@ -851,6 +876,25 @@ class ChildOutputTail:
851
876
  return lines
852
877
 
853
878
 
879
+ def raise_for_classified_verl_exit(return_code: int, tail: ChildOutputTail) -> None:
880
+ """raise a classified failure when a nonzero verl child reported authoritative evidence."""
881
+ if return_code == 0:
882
+ return
883
+ oom_evidence = tail.cuda_oom_evidence
884
+ if oom_evidence is not None:
885
+ raise RuntimeError(
886
+ f"verl subprocess exited with status {return_code} after reporting {oom_evidence}"
887
+ )
888
+ signature = tail.retriable_infra_signature
889
+ if signature is None:
890
+ return
891
+ from flash.engine.worker.perf.lifecycle import RetriableInfraError
892
+
893
+ raise RetriableInfraError(
894
+ f"verl subprocess exited with status {return_code} after reporting {signature}"
895
+ )
896
+
897
+
854
898
  class ChildTailStaleness:
855
899
  """tracks how long a child has been silent, across the ticks that sample its tail.
856
900
 
@@ -1073,6 +1117,7 @@ def run_verl_training(
1073
1117
  device memory that nothing will release.
1074
1118
  """
1075
1119
  step_re = re.compile(step_pattern)
1120
+ child_tail = tail if tail is not None else ChildOutputTail()
1076
1121
  # before the child exists, so any grandchild it orphans reparents here and can actually be
1077
1122
  # reaped. this process is not pid 1 -- the runpod handler is -- so without it every wait below
1078
1123
  # answers ChildProcessError for a zombie nobody will collect.
@@ -1086,13 +1131,14 @@ def run_verl_training(
1086
1131
  bufsize=1,
1087
1132
  start_new_session=True,
1088
1133
  )
1134
+ # start_new_session makes the leader pid the stable group id even after that leader is reaped.
1135
+ process_group_id = proc.pid
1089
1136
  last_hb = 0.0
1090
1137
  try:
1091
1138
  assert proc.stdout is not None
1092
1139
  for line in proc.stdout:
1093
1140
  print(line, end="", flush=True)
1094
- if tail is not None:
1095
- tail.record(line)
1141
+ child_tail.record(line)
1096
1142
  if on_line is not None:
1097
1143
  on_line(line)
1098
1144
  m = step_re.search(line)
@@ -1104,7 +1150,7 @@ def run_verl_training(
1104
1150
  heartbeat()
1105
1151
  last_hb = now
1106
1152
  except BaseException:
1107
- kill_process_group(proc)
1153
+ kill_process_group(proc, process_group_id=process_group_id)
1108
1154
  raise
1109
1155
  finally:
1110
1156
  if proc.poll() is None:
@@ -1114,7 +1160,13 @@ def run_verl_training(
1114
1160
  # caller of this -- runs on exceptions alone: a worker whose later jobs all succeed would
1115
1161
  # hold that zombie for its whole life, as pid 1 with nothing else to reap it (codex[bot]).
1116
1162
  reap_stragglers()
1117
- return int(proc.returncode)
1163
+ return_code = int(proc.returncode)
1164
+ try:
1165
+ raise_for_classified_verl_exit(return_code, child_tail)
1166
+ except BaseException:
1167
+ kill_process_group(proc, process_group_id=process_group_id)
1168
+ raise
1169
+ return return_code
1118
1170
 
1119
1171
 
1120
1172
  _TEARDOWN_GRACE_S = 10.0
@@ -1373,13 +1425,14 @@ def _process_group_members(pgid: int) -> list[int] | None:
1373
1425
  return members
1374
1426
 
1375
1427
 
1376
- def kill_process_group(proc: subprocess.Popen) -> None:
1428
+ def kill_process_group(proc: subprocess.Popen, *, process_group_id: int | None = None) -> None:
1377
1429
  """signal the child's whole process group, escalating to SIGKILL if anything survives.
1378
1430
 
1379
1431
  signalling the group rather than the pid is what reaches vllm's EngineCore grandchild; a survivor
1380
1432
  holds its cuda context and strands the gpu for every later run. the escalation is driven off the
1381
1433
  group, not off the direct child: the usual shape of this failure is the trainer dying on the term
1382
1434
  while the EngineCore ignores it, so waiting only on the child returns before the survivor is gone.
1435
+ a captured ``process_group_id`` keeps the group addressable after the direct child is reaped.
1383
1436
  """
1384
1437
  # grpo drives its own subprocess and calls this directly, never through `run_verl_training`, so
1385
1438
  # the adoption is claimed here too rather than only at the other entry point. idempotent.
@@ -1388,13 +1441,15 @@ def kill_process_group(proc: subprocess.Popen) -> None:
1388
1441
  # entry rather than on exit because that is when such a process has had the longest to die, and
1389
1442
  # it runs before the early returns below so no path through this function skips it.
1390
1443
  reap_stragglers()
1391
- try:
1392
- pgid = os.getpgid(proc.pid)
1393
- except OSError:
1394
- # already reaped, so there is no group id left to address the survivors by.
1395
- with contextlib.suppress(subprocess.TimeoutExpired):
1396
- proc.wait(timeout=_TEARDOWN_GRACE_S)
1397
- return
1444
+ pgid = process_group_id
1445
+ if pgid is None:
1446
+ try:
1447
+ pgid = os.getpgid(proc.pid)
1448
+ except OSError:
1449
+ # already reaped, so there is no group id left to address the survivors by.
1450
+ with contextlib.suppress(subprocess.TimeoutExpired):
1451
+ proc.wait(timeout=_TEARDOWN_GRACE_S)
1452
+ return
1398
1453
 
1399
1454
  with contextlib.suppress(ProcessLookupError, PermissionError, OSError):
1400
1455
  os.killpg(pgid, signal.SIGTERM)
@@ -1553,6 +1553,14 @@ def build_opd_overrides(config: dict) -> list[str]:
1553
1553
  f"actor_rollout_ref.model.lora_rank={_hydra_val(config['lora_rank'])}",
1554
1554
  f"actor_rollout_ref.model.lora_alpha={_hydra_val(config['lora_alpha'])}",
1555
1555
  f"actor_rollout_ref.model.target_modules={_hydra_val(config['target_modules'])}",
1556
+ *(
1557
+ [
1558
+ "++actor_rollout_ref.model.target_parameters="
1559
+ + _hydra_val(config["target_parameters"])
1560
+ ]
1561
+ if config.get("target_parameters")
1562
+ else []
1563
+ ),
1556
1564
  f"actor_rollout_ref.model.lora_adapter_path={_hydra_val(config.get('lora_adapter_path'))}",
1557
1565
  "actor_rollout_ref.actor.strategy=fsdp",
1558
1566
  "actor_rollout_ref.actor.use_kl_loss=false",
@@ -2498,6 +2506,7 @@ def run_opd_train(spec=None) -> None:
2498
2506
  "lora_rank": lora_rank,
2499
2507
  "lora_alpha": lora_alpha,
2500
2508
  "target_modules": target_modules,
2509
+ "target_parameters": _w.lora_target_parameters(model_id),
2501
2510
  "lora_adapter_path": warmstart_adapter,
2502
2511
  "learning_rate": knobs.learning_rate,
2503
2512
  "local_dir": local_dir,
@@ -6,6 +6,10 @@ import contextlib
6
6
  import re
7
7
 
8
8
  RETRIABLE_INFRA_MARKER = "RETRIABLE_INFRA_GPU"
9
+ _CUDA_OOM_PREFLIGHT_RE = re.compile(
10
+ r"free memory on device\s+cuda:\d+.*less than desired gpu memory utilization"
11
+ )
12
+ _CUDA_OOM_CACHE_BLOCKS = "no available memory for the cache blocks"
9
13
 
10
14
 
11
15
  class RetriableInfraError(RuntimeError):
@@ -30,6 +34,17 @@ def cuda_oom_count() -> int:
30
34
  return 0
31
35
 
32
36
 
37
+ def cuda_oom_message_evidence(message: str) -> str | None:
38
+ """the authoritative text evidence for a deterministic cuda oom, if present."""
39
+ normalized = message.lower()
40
+ preflight = _CUDA_OOM_PREFLIGHT_RE.search(normalized)
41
+ if preflight is not None:
42
+ return preflight.group(0)
43
+ if _CUDA_OOM_CACHE_BLOCKS in normalized:
44
+ return _CUDA_OOM_CACHE_BLOCKS
45
+ return None
46
+
47
+
33
48
  def is_cuda_oom(exc: BaseException | None) -> bool:
34
49
  """Whether a failure was a CUDA OOM.
35
50
 
@@ -46,13 +61,7 @@ def is_cuda_oom(exc: BaseException | None) -> bool:
46
61
  return True
47
62
  except Exception:
48
63
  pass
49
- msg = str(exc).lower()
50
- if (
51
- re.search(
52
- r"free memory on device\s+cuda:\d+.*less than desired gpu memory utilization", msg
53
- )
54
- or "no available memory for the cache blocks" in msg
55
- ):
64
+ if cuda_oom_message_evidence(str(exc)) is not None:
56
65
  return True
57
66
  return cuda_oom_count() > 0
58
67
 
@@ -49,6 +49,7 @@ from flash.engine.worker._pkg import W as _w
49
49
  from flash.engine.worker.backend_common import (
50
50
  VERL_REQUIREMENT,
51
51
  BoundedThreadingHTTPServer,
52
+ ChildOutputTail,
52
53
  adopt_orphaned_descendants,
53
54
  agent_loop_workers,
54
55
  append_step_metrics,
@@ -60,6 +61,7 @@ from flash.engine.worker.backend_common import (
60
61
  parse_verl_metric,
61
62
  parse_verl_step_metrics,
62
63
  parse_wandb_link,
64
+ raise_for_classified_verl_exit,
63
65
  ray_num_cpus,
64
66
  reap_stragglers,
65
67
  render_wandb_link_shim,
@@ -356,6 +358,11 @@ def build_verl_overrides(cfg: dict) -> list[str]:
356
358
  f"actor_rollout_ref.model.lora_rank={cfg['lora_rank']}",
357
359
  f"actor_rollout_ref.model.lora_alpha={cfg['lora_alpha']}",
358
360
  f"actor_rollout_ref.model.target_modules={cfg['target_modules']}",
361
+ *(
362
+ ["++actor_rollout_ref.model.target_parameters=" + _hydra_val(cfg["target_parameters"])]
363
+ if cfg.get("target_parameters")
364
+ else []
365
+ ),
359
366
  # memory: match the retired trl path's gradient checkpointing.
360
367
  "actor_rollout_ref.model.enable_gradient_checkpointing=True",
361
368
  # 32k contexts: fused linear-CE computes logprobs/entropy from hidden states + lm_head in
@@ -564,6 +571,7 @@ def _build_verl_training_cfg(
564
571
  "lora_rank": inp["lora_rank"],
565
572
  "lora_alpha": inp["lora_alpha"],
566
573
  "target_modules": "all-linear",
574
+ "target_parameters": _w.lora_target_parameters(model_id),
567
575
  "multimodal": bool(inp.get("multimodal")),
568
576
  "lr": inp["lr"],
569
577
  "group_size": inp["group_size"],
@@ -2756,6 +2764,7 @@ def _resolve_grpo_inputs():
2756
2764
  )
2757
2765
  with open(os.path.join(warmstart_adapter, "adapter_config.json")) as f:
2758
2766
  _src_cfg = json.load(f)
2767
+ _w.validate_lora_target_parameters(_src_cfg, model_id)
2759
2768
  # a patterned adapter trains some modules at higher rank than the base `r`; verl allocates
2760
2769
  # one uniform rank, so it must cover the MAXIMUM prepared rank or the load truncates.
2761
2770
  _ranks = [int(_src_cfg.get("r", lora_rank))]
@@ -3022,6 +3031,38 @@ def _resolve_grpo_inputs():
3022
3031
  }
3023
3032
 
3024
3033
 
3034
+ class _GrpoSubprocessStream:
3035
+ """one grpo child stream and the evidence latched from that same stream."""
3036
+
3037
+ def __init__(self, proc) -> None:
3038
+ self._proc = proc
3039
+ # the caller uses start_new_session, so the leader pid remains the group's stable identity.
3040
+ self._process_group_id = proc.pid
3041
+ self._tail = ChildOutputTail()
3042
+ self._terminated = False
3043
+
3044
+ def __iter__(self):
3045
+ assert self._proc.stdout is not None
3046
+ for line in self._proc.stdout:
3047
+ self._tail.record(line)
3048
+ yield line
3049
+
3050
+ def terminate(self) -> None:
3051
+ if self._terminated:
3052
+ return
3053
+ kill_process_group(self._proc, process_group_id=self._process_group_id)
3054
+ self._terminated = True
3055
+
3056
+ def wait_and_classify(self) -> int:
3057
+ return_code = int(self._proc.wait())
3058
+ try:
3059
+ raise_for_classified_verl_exit(return_code, self._tail)
3060
+ except BaseException:
3061
+ self.terminate()
3062
+ raise
3063
+ return return_code
3064
+
3065
+
3025
3066
  def run_rl_train():
3026
3067
  """grpo training on verl, output-compatible with run_rl. see module docstring for scope."""
3027
3068
  t_start = time.time()
@@ -3408,8 +3449,9 @@ def run_rl_train():
3408
3449
  env=env_for_verl,
3409
3450
  start_new_session=True,
3410
3451
  )
3452
+ child_stream = _GrpoSubprocessStream(proc)
3411
3453
  try:
3412
- for line in proc.stdout:
3454
+ for line in child_stream:
3413
3455
  print(f"[verl] {line}", end="", flush=True)
3414
3456
  link = parse_wandb_link(line)
3415
3457
  if link is not None:
@@ -3483,14 +3525,14 @@ def run_rl_train():
3483
3525
  adv_min = parse_verl_metric(line, "critic/advantages/min")
3484
3526
  if adv_max is not None and adv_min is not None:
3485
3527
  adv_spread_history.append(adv_max - adv_min)
3486
- rc = proc.wait()
3528
+ rc = child_stream.wait_and_classify()
3487
3529
  except BaseException:
3488
3530
  # the stream loop died (upload error, cancel, oom in the parent): a still-running
3489
3531
  # verl child would keep burning the gpu unattended, so kill its whole process group.
3490
3532
  # this escalates to SIGKILL after the grace period, which a bare SIGTERM does not: a
3491
3533
  # vllm EngineCore that ignores the term keeps its cuda context and strands the gpu
3492
3534
  # for every later job on a reusable worker.
3493
- kill_process_group(proc)
3535
+ child_stream.terminate()
3494
3536
  raise
3495
3537
  if rc != 0:
3496
3538
  raise RuntimeError(
@@ -166,6 +166,11 @@ def build_sft_overrides(cfg: dict) -> list[str]:
166
166
  f"model.lora_rank={_hydra_val(cfg['lora_rank'])}",
167
167
  f"model.lora_alpha={_hydra_val(cfg['lora_alpha'])}",
168
168
  f"model.target_modules={_hydra_val(cfg['target_modules'])}",
169
+ *(
170
+ [f"++model.target_parameters={_hydra_val(cfg['target_parameters'])}"]
171
+ if cfg.get("target_parameters")
172
+ else []
173
+ ),
169
174
  f"model.lora_adapter_path={_hydra_val(cfg.get('lora_adapter_path'))}",
170
175
  "model.use_remove_padding=true",
171
176
  # 32k contexts: the fused linear-CE forward never materializes the [tokens, vocab] logits
@@ -762,6 +767,7 @@ def _warmstart_adapter_path(model_id: str, model_revision: str, expected_rank: i
762
767
  f"SFT warm-start adapter rank {rank} does not match the prepared train.lora_rank "
763
768
  f"{expected_rank}; rank changes are not supported"
764
769
  )
770
+ _w.validate_lora_target_parameters(config, model_id)
765
771
  base = str(config.get("base_model_name_or_path") or "").strip()
766
772
  if base and base != model_id:
767
773
  raise ValueError("SFT warm-start adapter base model does not match the target model")
@@ -1270,6 +1276,7 @@ def run_sft_train(spec=None) -> None:
1270
1276
  "lora_rank": lora_rank,
1271
1277
  "lora_alpha": lora_alpha,
1272
1278
  "target_modules": target_modules,
1279
+ "target_parameters": _w.lora_target_parameters(model_id),
1273
1280
  "lora_adapter_path": warmstart_adapter,
1274
1281
  "ulysses_sp_size": gpu_count,
1275
1282
  "lr": learning_rate,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "freesolo-flash-dev"
3
- version = "1.0.83"
3
+ version = "1.0.85"
4
4
  description = "Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI"
5
5
  readme = "README.md"
6
6
  # RunPod Flash supports Python 3.11-3.12 (not 3.13 yet).
@@ -127,7 +127,7 @@ artifacts = ["flash/py.typed"]
127
127
  # auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
128
128
  # PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
129
129
  # dev-channel release = bump this (and [project].version) and merge to `dev`.
130
- version = "1.0.83"
130
+ version = "1.0.85"
131
131
 
132
132
  [tool.pytest.ini_options]
133
133
  pythonpath = ["."]
@@ -1073,7 +1073,7 @@ def test_catalog_model_algorithm_gpu_matrix_routes_to_fitting_cards(monkeypatch)
1073
1073
  from flash.catalog import ALGORITHMS, MODELS
1074
1074
  from flash.cost import RunConfig, estimate_cost
1075
1075
  from flash.providers import allocator
1076
- from flash.providers.base import get_gpu_info, provisional_gpu
1076
+ from flash.providers.base import GPU_INFO, combined_vram_gb, get_gpu_info, provisional_gpu
1077
1077
 
1078
1078
  monkeypatch.setattr(allocator, "available_providers", lambda: ("runpod",))
1079
1079
  expected = {
@@ -1090,25 +1090,50 @@ def test_catalog_model_algorithm_gpu_matrix_routes_to_fitting_cards(monkeypatch)
1090
1090
  continue
1091
1091
  train = {}
1092
1092
  need = allocator.required_vram_gb(model_id, algo, train=train, thinking=False)
1093
+ # most cells fit one card. the 35B MoE trains 256 routed experts per fused tensor, so its
1094
+ # GRPO/OPD peaks exceed every single card and the route is only defined across two.
1095
+ cards = 2 if need > max(g.vram_gb for g in GPU_INFO.values() if g.validated) else 1
1093
1096
 
1094
- preview_gpu = provisional_gpu(model_id, algo, train=train, thinking=False)
1097
+ preview_gpu = provisional_gpu(
1098
+ model_id, algo, train=train, thinking=False, gpu_count=cards
1099
+ )
1095
1100
  preview_info = get_gpu_info(preview_gpu)
1096
1101
  assert preview_info.validated
1097
1102
  assert preview_info.enum_member
1098
- assert preview_info.vram_gb >= need, (model_id, algo, preview_gpu, need)
1103
+ # sharding is not free: combined_vram_gb applies the per-card overhead, so two cards hold
1104
+ # less than twice one card. sizing with a naive sum would overstate what the shape holds.
1105
+ assert combined_vram_gb(preview_info.vram_gb, cards) >= need, (
1106
+ model_id,
1107
+ algo,
1108
+ preview_gpu,
1109
+ need,
1110
+ )
1099
1111
 
1100
- alloc = allocator.allocate(model_id, algo, train=train, thinking=False)
1112
+ alloc = allocator.allocate(
1113
+ model_id, algo, train=train, thinking=False, max_gpu_count=cards
1114
+ )
1101
1115
  alloc_info = get_gpu_info(alloc.gpu)
1102
1116
  assert alloc.provider == "runpod"
1103
1117
  assert alloc.min_vram_gb == need
1104
1118
  assert alloc_info.validated
1105
1119
  assert alloc_info.enum_member
1106
- assert alloc_info.vram_gb >= need, (model_id, algo, alloc.gpu, need)
1107
- assert all(c.vram_gb >= need for c in alloc.candidates)
1120
+ assert combined_vram_gb(alloc_info.vram_gb, cards) >= need, (
1121
+ model_id,
1122
+ algo,
1123
+ alloc.gpu,
1124
+ need,
1125
+ )
1126
+ assert all(combined_vram_gb(c.vram_gb, cards) >= need for c in alloc.candidates)
1108
1127
 
1109
- estimate = estimate_cost(RunConfig(model_id, algo, 1, provider="runpod"))
1110
- assert estimate.required_vram_gb == need
1111
- assert estimate.gpu_vram_gb >= need, (model_id, algo, estimate.gpu, need)
1128
+ estimate = estimate_cost(
1129
+ RunConfig(model_id, algo, 1, provider="runpod", gpu_count=cards)
1130
+ )
1131
+ assert estimate.gpu_vram_gb * estimate.gpu_count >= estimate.required_vram_gb, (
1132
+ model_id,
1133
+ algo,
1134
+ estimate.gpu,
1135
+ estimate.required_vram_gb,
1136
+ )
1112
1137
  checked.add((model_id, algo))
1113
1138
 
1114
1139
  assert checked == expected
@@ -1151,7 +1176,18 @@ def test_catalog_model_algorithm_config_gpu_matrix_enforces_pins(monkeypatch):
1151
1176
  }
1152
1177
  key = (model_id, algo, configured_gpu)
1153
1178
  if get_gpu_info(configured_gpu).vram_gb < need:
1154
- with pytest.raises(ConfigError, match="requires at least"):
1179
+ # two distinct rejections, both correct: a pin that is merely too small names the
1180
+ # shortfall, while a run that outgrows EVERY validated class (35B GRPO/OPD, once
1181
+ # the routed experts train) fails earlier with no fitting class at all.
1182
+ biggest = max(g.vram_gb for g in GPU_INFO.values() if g.validated)
1183
+ # opd words its over-capacity error differently from the generic allocator one,
1184
+ # so match the shared "no ... validated GPU" shape rather than either wording.
1185
+ reason = (
1186
+ "requires at least"
1187
+ if need <= biggest
1188
+ else r"(no validated GPU class has|more than any single validated GPU)"
1189
+ )
1190
+ with pytest.raises(ConfigError, match=reason):
1155
1191
  spec_from_dict(raw, run_id="matrix")
1156
1192
  rejected.add(key)
1157
1193
  continue