freesolo-flash-dev 1.0.45__tar.gz → 1.0.46__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 (396) hide show
  1. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/PKG-INFO +1 -1
  2. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl.py +17 -6
  3. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rl_verl.py +19 -0
  4. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/sft_verl.py +12 -0
  5. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/verl_common.py +74 -0
  6. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/pyproject.toml +2 -2
  7. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_rl_verl.py +120 -79
  8. freesolo_flash_dev-1.0.46/tests/test_verl_wandb_link.py +215 -0
  9. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/uv.lock +1 -1
  10. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.dockerignore +0 -0
  11. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.env.example +0 -0
  12. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  13. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  14. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  15. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  16. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/dependabot.yml +0 -0
  17. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/auto-rebake.yml +0 -0
  18. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/bake-kernel-cache.yml +0 -0
  19. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/ci.yml +0 -0
  20. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/main-source-guard.yml +0 -0
  21. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/notify-tests-repo.yml +0 -0
  22. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/publish-dev.yml +0 -0
  23. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/publish-image.yml +0 -0
  24. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/publish.yml +0 -0
  25. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/version-parity.yml +0 -0
  26. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/worker-image.yml +0 -0
  27. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.gitignore +0 -0
  28. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/CODE_OF_CONDUCT.md +0 -0
  29. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/CONTRIBUTING.md +0 -0
  30. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/Dockerfile +0 -0
  31. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/Dockerfile.worker +0 -0
  32. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/LICENSE +0 -0
  33. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/NOTICE +0 -0
  34. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/README.md +0 -0
  35. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/SECURITY.md +0 -0
  36. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/build/kernel_cache/.gitignore +0 -0
  37. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/build/kernel_cache/.keep +0 -0
  38. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/Dockerfile.kernelcache +0 -0
  39. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/Dockerfile.kernelcache.relayer +0 -0
  40. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/bake_kernel_cache.py +0 -0
  41. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/bake_pod_entry.py +0 -0
  42. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/kernel_fingerprint.py +0 -0
  43. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/make_rp_handler.py +0 -0
  44. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/__init__.py +0 -0
  45. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_channel.py +0 -0
  46. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_fileio.py +0 -0
  47. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_logging.py +0 -0
  48. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_update_check.py +0 -0
  49. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/adapter_artifacts.py +0 -0
  50. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/catalog.py +0 -0
  51. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/__init__.py +0 -0
  52. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/__main__.py +0 -0
  53. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/_tty.py +0 -0
  54. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/commands.py +0 -0
  55. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/env_setup.py +0 -0
  56. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/env_test.py +0 -0
  57. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/envpush.py +0 -0
  58. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/render.py +0 -0
  59. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/traces.py +0 -0
  60. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/training_doc.py +0 -0
  61. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/__init__.py +0 -0
  62. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/config.py +0 -0
  63. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/http.py +0 -0
  64. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/runtime_secrets.py +0 -0
  65. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/specs.py +0 -0
  66. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/__init__.py +0 -0
  67. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/analytical.py +0 -0
  68. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/facts.py +0 -0
  69. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/spec.py +0 -0
  70. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/types.py +0 -0
  71. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/diagnostics.py +0 -0
  72. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/__init__.py +0 -0
  73. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/accounting.py +0 -0
  74. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/chalk_kernels.py +0 -0
  75. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/multiturn_reward_scoring.py +0 -0
  76. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/multiturn_rollout.py +0 -0
  77. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/recipe.py +0 -0
  78. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/steps.py +0 -0
  79. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/structured_outputs.py +0 -0
  80. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/vram.py +0 -0
  81. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/__init__.py +0 -0
  82. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/__main__.py +0 -0
  83. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/_pkg.py +0 -0
  84. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/adapter.py +0 -0
  85. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/decoding.py +0 -0
  86. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/finalize.py +0 -0
  87. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/gpu_setup.py +0 -0
  88. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/grpo.py +0 -0
  89. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/grpo_multimodal.py +0 -0
  90. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/grpo_perturn_trainer.py +0 -0
  91. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/heartbeat.py +0 -0
  92. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/hf.py +0 -0
  93. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/kernel_warmup.py +0 -0
  94. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/lora.py +0 -0
  95. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd.py +0 -0
  96. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_gkd.py +0 -0
  97. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl_multiturn.py +0 -0
  98. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl_plugin.py +0 -0
  99. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl_structured.py +0 -0
  100. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_vllm.py +0 -0
  101. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/packing.py +0 -0
  102. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/__init__.py +0 -0
  103. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/attn.py +0 -0
  104. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/diagnostics.py +0 -0
  105. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/lifecycle.py +0 -0
  106. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/liger.py +0 -0
  107. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/loraplus.py +0 -0
  108. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/memory.py +0 -0
  109. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rl.py +0 -0
  110. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rng.py +0 -0
  111. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rollout_samples.py +0 -0
  112. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/sft.py +0 -0
  113. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/teacher.py +0 -0
  114. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/tokenizer_align.py +0 -0
  115. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/wandb_log.py +0 -0
  116. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker_entrypoint.py +0 -0
  117. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/__init__.py +0 -0
  118. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/adapter.py +0 -0
  119. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/archive.py +0 -0
  120. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/archive_policy.py +0 -0
  121. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/base.py +0 -0
  122. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/loader.py +0 -0
  123. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/pull.py +0 -0
  124. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/registry.py +0 -0
  125. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/lora_rank.py +0 -0
  126. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/multimodal.py +0 -0
  127. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/opd_retry_contract.py +0 -0
  128. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/opd_verl_validation.py +0 -0
  129. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/__init__.py +0 -0
  130. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_auth.py +0 -0
  131. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_deadline.py +0 -0
  132. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_hf_artifacts.py +0 -0
  133. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_hf_retry.py +0 -0
  134. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_http.py +0 -0
  135. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance.py +0 -0
  136. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance_bootstrap.py +0 -0
  137. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance_poll.py +0 -0
  138. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance_provider.py +0 -0
  139. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_poll.py +0 -0
  140. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_worker.py +0 -0
  141. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/allocator.py +0 -0
  142. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/base.py +0 -0
  143. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/__init__.py +0 -0
  144. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/api.py +0 -0
  145. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/auth.py +0 -0
  146. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/gpus.py +0 -0
  147. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
  148. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/jobs/builders.py +0 -0
  149. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/preflight.py +0 -0
  150. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/pricing.py +0 -0
  151. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/preflight.py +0 -0
  152. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/realized.py +0 -0
  153. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/__init__.py +0 -0
  154. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/api.py +0 -0
  155. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/auth.py +0 -0
  156. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/cost.py +0 -0
  157. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/gpus.py +0 -0
  158. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/jobs.py +0 -0
  159. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/keys.py +0 -0
  160. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/preflight.py +0 -0
  161. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/pricing.py +0 -0
  162. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/slots.py +0 -0
  163. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/train/__init__.py +0 -0
  164. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/train/endpoints.py +0 -0
  165. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/__init__.py +0 -0
  166. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/api.py +0 -0
  167. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/auth.py +0 -0
  168. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/jobs/__init__.py +0 -0
  169. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/jobs/builders.py +0 -0
  170. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/preflight.py +0 -0
  171. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/pricing.py +0 -0
  172. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/weight_cache_preload.py +0 -0
  173. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/py.typed +0 -0
  174. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/__init__.py +0 -0
  175. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/checkpoints.py +0 -0
  176. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/deploy.py +0 -0
  177. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/lifecycle.py +0 -0
  178. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/verified_revisions.py +0 -0
  179. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/schema/__init__.py +0 -0
  180. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/schema/fields.py +0 -0
  181. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/__init__.py +0 -0
  182. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/deploy.py +0 -0
  183. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/export.py +0 -0
  184. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/preflight.py +0 -0
  185. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/pricing.py +0 -0
  186. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/urls.py +0 -0
  187. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/__init__.py +0 -0
  188. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/__main__.py +0 -0
  189. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_deps.py +0 -0
  190. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_internal_client.py +0 -0
  191. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_locks.py +0 -0
  192. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_runtime.py +0 -0
  193. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/app.py +0 -0
  194. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/auth.py +0 -0
  195. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/billing.py +0 -0
  196. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/billing_retry.py +0 -0
  197. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/checkpoints.py +0 -0
  198. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/db.py +0 -0
  199. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/environment_registry.py +0 -0
  200. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/envs.py +0 -0
  201. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/projects.py +0 -0
  202. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/reconcile.py +0 -0
  203. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/repo_cleanup.py +0 -0
  204. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/__init__.py +0 -0
  205. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/envs.py +0 -0
  206. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/meta.py +0 -0
  207. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/runs.py +0 -0
  208. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/serving.py +0 -0
  209. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/run_registry.py +0 -0
  210. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/spec.py +0 -0
  211. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/infisical-entrypoint.sh +0 -0
  212. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/scripts/build_dev_dist.py +0 -0
  213. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/scripts/scrub_history.sh +0 -0
  214. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/__init__.py +0 -0
  215. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/__init__.py +0 -0
  216. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/runner.py +0 -0
  217. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/specs.py +0 -0
  218. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/vast.py +0 -0
  219. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/conftest.py +0 -0
  220. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/fixtures/math_eval.jsonl +0 -0
  221. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/fixtures/math_train.jsonl +0 -0
  222. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/__init__.py +0 -0
  223. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/conftest.py +0 -0
  224. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/test_lambda_live.py +0 -0
  225. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/test_runpod_live.py +0 -0
  226. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/test_vast_live.py +0 -0
  227. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_accounting_coverage.py +0 -0
  228. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_agent_flash_cli_contract.py +0 -0
  229. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_algorithms.py +0 -0
  230. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_allocator.py +0 -0
  231. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_async_uploads.py +0 -0
  232. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_b200_rollout_opt.py +0 -0
  233. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_backend_jobspec_contract.py +0 -0
  234. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_base_model_provenance.py +0 -0
  235. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_billing_retry.py +0 -0
  236. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cancel_remote.py +0 -0
  237. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_catalog_consistency.py +0 -0
  238. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_chalk_kernels.py +0 -0
  239. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_charge_pricing.py +0 -0
  240. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_checkpoints.py +0 -0
  241. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_commands.py +0 -0
  242. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_commands_coverage.py +0 -0
  243. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_errors.py +0 -0
  244. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_estimate.py +0 -0
  245. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_help.py +0 -0
  246. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_main_coverage.py +0 -0
  247. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_managed.py +0 -0
  248. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_render_coverage.py +0 -0
  249. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_render_theme.py +0 -0
  250. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_traces.py +0 -0
  251. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_client.py +0 -0
  252. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_client_server_integration.py +0 -0
  253. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_client_stream_reads.py +0 -0
  254. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_config_overrides.py +0 -0
  255. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_controlled_experiment_repairs.py +0 -0
  256. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_analytical.py +0 -0
  257. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_equation.py +0 -0
  258. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_estimate.py +0 -0
  259. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_hardware.py +0 -0
  260. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_models.py +0 -0
  261. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_rewards.py +0 -0
  262. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_deploy_latency.py +0 -0
  263. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_dev_channel.py +0 -0
  264. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_disk_gb.py +0 -0
  265. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_endpoint_name.py +0 -0
  266. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_cache_evict.py +0 -0
  267. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_delete.py +0 -0
  268. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_download.py +0 -0
  269. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_download_api.py +0 -0
  270. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_no_install.py +0 -0
  271. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_publish.py +0 -0
  272. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull.py +0 -0
  273. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull_coverage.py +0 -0
  274. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull_loader_coverage.py +0 -0
  275. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull_managed_control_plane.py +0 -0
  276. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_push.py +0 -0
  277. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_rate_limit_resolve.py +0 -0
  278. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_test.py +0 -0
  279. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_envs_coverage.py +0 -0
  280. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_export.py +0 -0
  281. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_flash_mvp.py +0 -0
  282. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_flash_worker.py +0 -0
  283. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_flashinfer_cache_dirs.py +0 -0
  284. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_github_urlopen_retry.py +0 -0
  285. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_gpu_type_single_field.py +0 -0
  286. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_gpus.py +0 -0
  287. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_cudagraphs.py +0 -0
  288. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_mask_aware.py +0 -0
  289. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_params.py +0 -0
  290. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_perturn.py +0 -0
  291. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_sleep_gate.py +0 -0
  292. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_health_liveness.py +0 -0
  293. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_hf_retry.py +0 -0
  294. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_idle_endpoint_reaper.py +0 -0
  295. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_instance_bootstrap_coverage.py +0 -0
  296. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_internal_client.py +0 -0
  297. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_jobs.py +0 -0
  298. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_kernel_cache.py +0 -0
  299. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_kernel_fingerprint.py +0 -0
  300. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_kv_util.py +0 -0
  301. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lambda_api_coverage.py +0 -0
  302. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lambda_runner.py +0 -0
  303. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_logging.py +0 -0
  304. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_login_perms.py +0 -0
  305. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lora_rank_coverage.py +0 -0
  306. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lora_rank_preflight.py +0 -0
  307. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_managed_config_fields.py +0 -0
  308. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_managed_hf_repo.py +0 -0
  309. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_metrics_schema_agent_contract.py +0 -0
  310. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_mig_guard.py +0 -0
  311. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multi_gpu_gate.py +0 -0
  312. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multimodal_input_grads.py +0 -0
  313. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multimodal_training.py +0 -0
  314. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_image_rollout.py +0 -0
  315. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_per_turn_reward.py +0 -0
  316. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout.py +0 -0
  317. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout_coverage.py +0 -0
  318. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout_records.py +0 -0
  319. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout_request_policy.py +0 -0
  320. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_named_reward_metrics.py +0 -0
  321. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_oom_escalate_gpu.py +0 -0
  322. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd.py +0 -0
  323. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_full_state_resume.py +0 -0
  324. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_resume_safety.py +0 -0
  325. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_verl.py +0 -0
  326. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_vllm.py +0 -0
  327. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_open_model_policy.py +0 -0
  328. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_orchestrator_flash.py +0 -0
  329. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_packing.py +0 -0
  330. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_packing_coverage.py +0 -0
  331. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_poll_helpers.py +0 -0
  332. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_preflight.py +0 -0
  333. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_projects.py +0 -0
  334. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_provider_preflight_coverage.py +0 -0
  335. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_provider_routing.py +0 -0
  336. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_provider_teardown_robustness.py +0 -0
  337. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_providers_symmetry.py +0 -0
  338. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_realized_cost.py +0 -0
  339. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_repo_cleanup.py +0 -0
  340. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_resolve_params_b.py +0 -0
  341. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_resume_on_retry.py +0 -0
  342. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_rollout_samples.py +0 -0
  343. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runmgmt.py +0 -0
  344. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_api_delete.py +0 -0
  345. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_key_fingerprint.py +0 -0
  346. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_key_waterfall.py +0 -0
  347. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_slots.py +0 -0
  348. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serve.py +0 -0
  349. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_api.py +0 -0
  350. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_app_coverage.py +0 -0
  351. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_auth_singleflight.py +0 -0
  352. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_billing.py +0 -0
  353. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_checkpoints_coverage.py +0 -0
  354. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_db.py +0 -0
  355. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_envs_coverage.py +0 -0
  356. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_locks_coverage.py +0 -0
  357. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_context_preflight.py +0 -0
  358. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_contract.py +0 -0
  359. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_pricing_coverage.py +0 -0
  360. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_schema_coverage.py +0 -0
  361. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_activation_shaping.py +0 -0
  362. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_chunked_nll.py +0 -0
  363. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_example_selection.py +0 -0
  364. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_gc_off.py +0 -0
  365. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_max_context.py +0 -0
  366. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_tokenize_cache.py +0 -0
  367. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_verl.py +0 -0
  368. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_single_turn_multimodal_grpo.py +0 -0
  369. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_spec_and_validation.py +0 -0
  370. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_structured_outputs.py +0 -0
  371. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_thinking_config.py +0 -0
  372. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_train_context_preflight.py +0 -0
  373. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_training_controls.py +0 -0
  374. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_update_check.py +0 -0
  375. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_api.py +0 -0
  376. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_api_coverage.py +0 -0
  377. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_offers.py +0 -0
  378. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_provider_coverage.py +0 -0
  379. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_runner.py +0 -0
  380. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_verified_revisions.py +0 -0
  381. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_verifiers.py +0 -0
  382. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_verl_common.py +0 -0
  383. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_version.py +0 -0
  384. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  385. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vram_architecture.py +0 -0
  386. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_wandb_log_coverage.py +0 -0
  387. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_wandb_naming.py +0 -0
  388. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_warmstart_adapter_download.py +0 -0
  389. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_warmstart_cross_repo.py +0 -0
  390. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_weight_cache.py +0 -0
  391. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_dryrun.py +0 -0
  392. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_hardexit.py +0 -0
  393. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_image.py +0 -0
  394. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_init_heartbeat.py +0 -0
  395. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_stack.py +0 -0
  396. {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/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.45
3
+ Version: 1.0.46
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
@@ -71,6 +71,8 @@ from flash.engine.worker.verl_common import (
71
71
  clamp_engine_len,
72
72
  latest_global_step_dir,
73
73
  model_max_position_embeddings,
74
+ parse_wandb_link,
75
+ render_wandb_link_shim,
74
76
  resolve_verl_python,
75
77
  run_verl_training,
76
78
  )
@@ -2344,13 +2346,14 @@ def run_opd_verl(spec=None) -> None:
2344
2346
  entry_path = os.path.join(shim_dir, "flash_opd_verl_entry.py")
2345
2347
  with open(entry_path, "w", encoding="utf-8") as file:
2346
2348
  file.write("import verl\nfrom flash_opd_verl_plugin import main\nmain()\n")
2349
+ opd_shim_source = _render_opd_sitecustomize(
2350
+ save_at_steps=knobs.save_at_steps,
2351
+ total_steps=update_horizon,
2352
+ )
2353
+ if "wandb" in loggers:
2354
+ opd_shim_source += render_wandb_link_shim()
2347
2355
  with open(os.path.join(shim_dir, "sitecustomize.py"), "w", encoding="utf-8") as file:
2348
- file.write(
2349
- _render_opd_sitecustomize(
2350
- save_at_steps=knobs.save_at_steps,
2351
- total_steps=update_horizon,
2352
- )
2353
- )
2356
+ file.write(opd_shim_source)
2354
2357
 
2355
2358
  resume_step, resume_state = _restore_verl_resume(
2356
2359
  local_dir,
@@ -2451,9 +2454,13 @@ def run_opd_verl(spec=None) -> None:
2451
2454
  )
2452
2455
  command = [python_bin, entry_path, *overrides]
2453
2456
  progress = {"step": resume_step, "loss": None}
2457
+ wandb_link: dict[str, str | None] = {}
2454
2458
 
2455
2459
  def on_line(line: str) -> None:
2456
2460
  watcher.raise_if_failed()
2461
+ link = parse_wandb_link(line)
2462
+ if link is not None:
2463
+ wandb_link.update(link)
2457
2464
  step_match = _VERL_STEP_RE.search(line)
2458
2465
  if step_match is None:
2459
2466
  return
@@ -2669,6 +2676,10 @@ def run_opd_verl(spec=None) -> None:
2669
2676
  "resumed": bool(resume_step),
2670
2677
  "wandb_project": project_name if "wandb" in loggers else None,
2671
2678
  "wandb_run_name": experiment_name if "wandb" in loggers else None,
2679
+ # the sdk's link_wandb reads notes["wandb_url"]; trl gets it from the parent's live
2680
+ # wandb.run, verl from the child marker (see verl_common.render_wandb_link_shim).
2681
+ "wandb_url": wandb_link.get("wandb_url"),
2682
+ "wandb_id": wandb_link.get("wandb_id"),
2672
2683
  },
2673
2684
  )
2674
2685
  finally:
@@ -52,6 +52,8 @@ from flash.engine.worker.verl_common import (
52
52
  agent_loop_workers,
53
53
  clamp_engine_len,
54
54
  model_max_position_embeddings,
55
+ parse_wandb_link,
56
+ render_wandb_link_shim,
55
57
  resolve_verl_python,
56
58
  verl_supports_rollout_field,
57
59
  )
@@ -370,6 +372,8 @@ def _build_verl_train_notes(
370
372
  fp8_kv: bool = False,
371
373
  wandb_project: str | None = None,
372
374
  wandb_run_name: str | None = None,
375
+ wandb_url: str | None = None,
376
+ wandb_id: str | None = None,
373
377
  ) -> dict:
374
378
  return {
375
379
  "backend": "verl",
@@ -419,6 +423,10 @@ def _build_verl_train_notes(
419
423
  "ppo_max_token_len_per_gpu": inp["engine_len"],
420
424
  "wandb_project": wandb_project,
421
425
  "wandb_run_name": wandb_run_name,
426
+ # the sdk's link_wandb reads notes["wandb_url"]; trl gets it from the parent's live
427
+ # wandb.run, verl from the child marker (see verl_common.render_wandb_link_shim).
428
+ "wandb_url": wandb_url,
429
+ "wandb_id": wandb_id,
422
430
  "grpo_recipe": {
423
431
  "kl_coef": inp["kl_coef"],
424
432
  "entropy_quantile": inp["entropy_quantile"],
@@ -1420,6 +1428,10 @@ def run_rl_verl():
1420
1428
  render_stop_sequences_shim(inp["stop_sequences"]),
1421
1429
  render_structured_outputs_shim(inp["structured_outputs"]),
1422
1430
  render_exact_save_steps_shim(inp["save_at_steps"], inp["steps"]),
1431
+ # gated on the key rather than the resolved logger list: that list needs python_bin,
1432
+ # which is resolved after this file is written. the shim is inert either way -- it only
1433
+ # fires when verl actually calls wandb.init, which requires wandb in the logger list.
1434
+ render_wandb_link_shim() if os.environ.get("WANDB_API_KEY") else "",
1423
1435
  )
1424
1436
  if part
1425
1437
  )
@@ -1433,6 +1445,8 @@ def run_rl_verl():
1433
1445
  # rolling buffer of recent (completion, score) so the training loop can dump one sample per step
1434
1446
  # to the flash log, matching the trl path's #607 per-step completion dump.
1435
1447
  recent_samples: list[tuple[str, float]] = []
1448
+ # filled from the child's marker line; stays empty when wandb is off (see render_wandb_link_shim).
1449
+ wandb_link: dict[str, str | None] = {}
1436
1450
  _samples_lock = threading.Lock()
1437
1451
 
1438
1452
  def _score(index: int, solution_str: str) -> float:
@@ -1560,6 +1574,9 @@ def run_rl_verl():
1560
1574
  try:
1561
1575
  for line in proc.stdout:
1562
1576
  print(f"[verl] {line}", end="", flush=True)
1577
+ link = parse_wandb_link(line)
1578
+ if link is not None:
1579
+ wandb_link.update(link)
1563
1580
  m = step_re.search(line)
1564
1581
  if m:
1565
1582
  step_box[0] = int(m.group(1))
@@ -1670,5 +1687,7 @@ def run_rl_verl():
1670
1687
  fp8_kv=fp8_kv,
1671
1688
  wandb_project=project_name if "wandb" in loggers else None,
1672
1689
  wandb_run_name=experiment_name if "wandb" in loggers else None,
1690
+ wandb_url=wandb_link.get("wandb_url"),
1691
+ wandb_id=wandb_link.get("wandb_id"),
1673
1692
  ),
1674
1693
  )
@@ -42,6 +42,8 @@ from flash.engine.worker.sft import (
42
42
  from flash.engine.worker.verl_common import (
43
43
  export_peft_adapter,
44
44
  latest_global_step_dir,
45
+ parse_wandb_link,
46
+ render_wandb_link_shim,
45
47
  resolve_verl_python,
46
48
  run_verl_training,
47
49
  stamp_adapter_dir_provenance,
@@ -1282,6 +1284,8 @@ def run_sft_verl(spec=None) -> None:
1282
1284
  total_steps=update_horizon,
1283
1285
  reentrant_gradient_checkpointing=reentrant_gradient_checkpointing,
1284
1286
  )
1287
+ if "wandb" in loggers:
1288
+ shim_source += render_wandb_link_shim()
1285
1289
  with open(os.path.join(shim_dir, "sitecustomize.py"), "w", encoding="utf-8") as file:
1286
1290
  file.write(shim_source)
1287
1291
  with open(custom_dataset_path, "w", encoding="utf-8") as file:
@@ -1327,12 +1331,16 @@ def run_sft_verl(spec=None) -> None:
1327
1331
  resume_step,
1328
1332
  )
1329
1333
  loraplus_applied = resume_step >= update_horizon
1334
+ wandb_link: dict[str, str | None] = {}
1330
1335
 
1331
1336
  def on_line(line: str) -> None:
1332
1337
  nonlocal loraplus_applied
1333
1338
  watcher.raise_if_failed()
1334
1339
  if _LORAPLUS_READY_MARKER in line:
1335
1340
  loraplus_applied = True
1341
+ link = parse_wandb_link(line)
1342
+ if link is not None:
1343
+ wandb_link.update(link)
1336
1344
  step_match = _VERL_STEP_RE.search(line)
1337
1345
  if step_match is None:
1338
1346
  return
@@ -1458,5 +1466,9 @@ def run_sft_verl(spec=None) -> None:
1458
1466
  "ulysses_sequence_parallel_size": gpu_count,
1459
1467
  "wandb_project": project_name if "wandb" in loggers else None,
1460
1468
  "wandb_run_name": experiment_name if "wandb" in loggers else None,
1469
+ # the sdk's link_wandb reads notes["wandb_url"]; trl gets it from the parent's live
1470
+ # wandb.run, verl from the child marker (see verl_common.render_wandb_link_shim).
1471
+ "wandb_url": wandb_link.get("wandb_url"),
1472
+ "wandb_id": wandb_link.get("wandb_id"),
1461
1473
  },
1462
1474
  )
@@ -317,3 +317,77 @@ def _kill_process_group(proc: subprocess.Popen) -> None:
317
317
  os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
318
318
  with contextlib.suppress(subprocess.TimeoutExpired):
319
319
  proc.wait(timeout=10)
320
+
321
+
322
+ # --------------------------- w&b run link (all three verl backends) ---------------------------
323
+ # trl spreads wandb_run_info() into its notes, giving the sdk's link_wandb a clickable
324
+ # notes["wandb_url"]. verl calls wandb.init INSIDE the training subprocess, so the flash parent's
325
+ # wandb.run is None and that spread would be a silent no-op. the url is not derivable up here
326
+ # either: it needs entity/project/runs/<wandb-generated-id>, and flash only knows the project and
327
+ # its own run NAME. so the child reports it back over the marker channel the parent already scans.
328
+ FLASH_WANDB_LINK_MARKER = "FLASH_WANDB_LINK"
329
+
330
+ _WANDB_LINK_RE = re.compile(rf"{FLASH_WANDB_LINK_MARKER}\s+(\{{.*\}})\s*$")
331
+
332
+
333
+ def render_wandb_link_shim() -> str:
334
+ """child-side sitecustomize fragment that reports the live w&b run's url and id.
335
+
336
+ wraps wandb.init rather than reading wandb.run at import time: sitecustomize runs long before
337
+ verl's tracking module initializes the run, so anything read here would always be None.
338
+
339
+ never raises. wandb is optional and a logging link must not be able to abort paid training, so
340
+ every failure path leaves the run unlinked instead of dead.
341
+ """
342
+ return f'''
343
+ # --- flash: report the w&b run link to the parent (see verl_common.render_wandb_link_shim) ---
344
+ try:
345
+ import json as _flash_wandb_json
346
+
347
+ import wandb as _flash_wandb
348
+
349
+ _flash_wandb_init = _flash_wandb.init
350
+
351
+ def _flash_wandb_init_reporting(*args, **kwargs):
352
+ _run = _flash_wandb_init(*args, **kwargs)
353
+ try:
354
+ _url = getattr(_run, "url", None)
355
+ _id = getattr(_run, "id", None)
356
+ if _url:
357
+ print(
358
+ "{FLASH_WANDB_LINK_MARKER} "
359
+ + _flash_wandb_json.dumps({{"wandb_url": _url, "wandb_id": _id}}),
360
+ flush=True,
361
+ )
362
+ except Exception:
363
+ pass
364
+ return _run
365
+
366
+ _flash_wandb.init = _flash_wandb_init_reporting
367
+ except Exception:
368
+ pass
369
+ '''
370
+
371
+
372
+ def parse_wandb_link(line: str) -> dict | None:
373
+ """the {{wandb_url, wandb_id}} a marker line carries, or None for every other line.
374
+
375
+ returns None rather than raising on a malformed payload: this parses child stdout, and a
376
+ truncated or interleaved line under multi-rank logging must not take down the run.
377
+ """
378
+ match = _WANDB_LINK_RE.search(line)
379
+ if match is None:
380
+ return None
381
+ try:
382
+ payload = json.loads(match.group(1))
383
+ except ValueError:
384
+ return None
385
+ if not isinstance(payload, dict):
386
+ return None
387
+ url = payload.get("wandb_url")
388
+ # https only: the sdk renders this as a clickable dashboard link, and child stdout also carries
389
+ # rollout text, so the field must not be able to become an arbitrary scheme.
390
+ if not isinstance(url, str) or not url.startswith("https://"):
391
+ return None
392
+ wandb_id = payload.get("wandb_id")
393
+ return {"wandb_url": url, "wandb_id": wandb_id if isinstance(wandb_id, str) else None}
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "freesolo-flash-dev"
3
- version = "1.0.45"
3
+ version = "1.0.46"
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).
@@ -116,7 +116,7 @@ artifacts = ["flash/py.typed"]
116
116
  # auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
117
117
  # PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
118
118
  # dev-channel release = bump this (and [project].version) and merge to `dev`.
119
- version = "1.0.45"
119
+ version = "1.0.46"
120
120
 
121
121
  [tool.pytest.ini_options]
122
122
  pythonpath = ["."]
@@ -322,48 +322,8 @@ def test_resolver_clamps_prompt_budget_with_the_engine(monkeypatch):
322
322
  # UNCLAMPED context. those prompts plus the completion allowance overflow the engine vllm was
323
323
  # actually given, so they die at rollout instead of training on the shorter context. every
324
324
  # length must descend from one clamped value.
325
- from flash.engine.worker._pkg import W
326
- from flash.spec import JobSpec
327
-
328
- class _Env:
329
- multi_turn = False
330
- is_tool_env = False
331
-
332
- def dataset(self):
333
- return [{"index": i} for i in range(8)]
334
-
335
- def prompt_messages(self, ex):
336
- return [{"role": "user", "content": f"question {ex['index']}"}]
337
-
338
- class _Tokenizer:
339
- pad_token = None
340
- eos_token = "<eos>"
341
-
342
- def apply_chat_template(self, messages, **kwargs):
343
- return messages[0]["content"]
344
-
345
- def __call__(self, text, **kwargs):
346
- return SimpleNamespace(input_ids=[1])
347
-
348
- spec = JobSpec.from_dict(
349
- {
350
- "model": "Qwen/Qwen3.5-0.8B",
351
- "algorithm": "grpo",
352
- # asks for twice the architecture's context.
353
- "train": {"batch_size": 4, "epochs": 1, "max_context_tokens": 65536},
354
- }
355
- )
356
- monkeypatch.setattr(W, "JOB_SPEC", spec, raising=False)
357
- monkeypatch.setattr(W, "SEED", 42, raising=False)
358
- monkeypatch.setattr(W, "THINKING", False, raising=False)
359
- monkeypatch.setattr(W, "require_active_env", lambda: _Env(), raising=False)
360
- monkeypatch.setattr(W, "grpo_overrides", lambda: {}, raising=False)
361
- monkeypatch.setattr(W, "grpo_mask_truncated_completions", lambda train: False, raising=False)
362
- monkeypatch.setattr(W, "load_tokenizer", lambda *args, **kwargs: _Tokenizer(), raising=False)
363
- monkeypatch.setattr(rl_verl, "seed_training_rngs", lambda seed: None)
364
- monkeypatch.setattr(rl_verl, "model_max_position_embeddings", lambda *a, **k: 32768)
365
-
366
- inp = rl_verl._resolve_single_turn_inputs()
325
+ # asks for twice the architecture's context (model_max_position_embeddings is pinned to 32768).
326
+ inp = _capability_resolve(monkeypatch, _capability_env(), train={"max_context_tokens": 65536})
367
327
  assert inp["engine_len"] == 32768
368
328
  # the prompt filter's budget is carved out of the clamped engine, not the requested 65536.
369
329
  assert inp["max_prompt_len"] + inp["max_completion"] == 32768
@@ -388,47 +348,12 @@ def test_resolver_clamps_prompt_budget_with_the_engine(monkeypatch):
388
348
 
389
349
  def _save_steps_inputs(monkeypatch, *, save_at_steps=None, save_every=None, max_steps=100):
390
350
  """resolve grpo verl inputs for a job with (or without) exact save steps."""
391
- from flash.engine.worker._pkg import W
392
- from flash.spec import JobSpec
393
-
394
- class _Env:
395
- multi_turn = False
396
- is_tool_env = False
397
-
398
- def dataset(self):
399
- return [{"index": i} for i in range(8)]
400
-
401
- def prompt_messages(self, ex):
402
- return [{"role": "user", "content": f"question {ex['index']}"}]
403
-
404
- class _Tokenizer:
405
- pad_token = None
406
- eos_token = "<eos>"
407
-
408
- def apply_chat_template(self, messages, **kwargs):
409
- return messages[0]["content"]
410
-
411
- def __call__(self, text, **kwargs):
412
- return SimpleNamespace(input_ids=[1])
413
-
414
- train: dict = {"batch_size": 4, "epochs": 1, "max_steps": max_steps}
351
+ train: dict = {"max_steps": max_steps}
415
352
  if save_at_steps is not None:
416
353
  train["save_at_steps"] = list(save_at_steps)
417
354
  if save_every is not None:
418
355
  train["save_every"] = save_every
419
- spec = JobSpec.from_dict(
420
- {"model": "Qwen/Qwen3.5-0.8B", "algorithm": "grpo", "train": train}
421
- )
422
- monkeypatch.setattr(W, "JOB_SPEC", spec, raising=False)
423
- monkeypatch.setattr(W, "SEED", 42, raising=False)
424
- monkeypatch.setattr(W, "THINKING", False, raising=False)
425
- monkeypatch.setattr(W, "require_active_env", lambda: _Env(), raising=False)
426
- monkeypatch.setattr(W, "grpo_overrides", lambda: {}, raising=False)
427
- monkeypatch.setattr(W, "grpo_mask_truncated_completions", lambda train: False, raising=False)
428
- monkeypatch.setattr(W, "load_tokenizer", lambda *args, **kwargs: _Tokenizer(), raising=False)
429
- monkeypatch.setattr(rl_verl, "seed_training_rngs", lambda seed: None)
430
- monkeypatch.setattr(rl_verl, "model_max_position_embeddings", lambda *a, **k: 32768)
431
- return rl_verl._resolve_single_turn_inputs()
356
+ return _capability_resolve(monkeypatch, _capability_env(), train=train)
432
357
 
433
358
 
434
359
  def test_save_freq_is_the_gcd_so_verl_lands_on_every_required_step(monkeypatch):
@@ -1343,3 +1268,119 @@ def test_train_notes_report_token_bounded_batching_as_unset_not_fabricated():
1343
1268
  assert notes["ppo_max_token_len_per_gpu"] == 4096
1344
1269
  # trl pins vllm's prefill batch because it hardcodes 4096; this path sets no such override.
1345
1270
  assert notes["vllm_max_num_batched_tokens"] is None
1271
+
1272
+
1273
+ # ------------------- capability guards: the four specs verl grpo refuses -------------------
1274
+ # these four raises are the ONLY thing standing between a trl-supported job and a verl run that
1275
+ # trains on a different contract. they had no regression coverage: every resolver test above drives
1276
+ # the happy path, so deleting any guard left the suite green. each test below asserts one rejection
1277
+ # by its own message, because a bare pytest.raises(RuntimeError) passes on any of the ~20 other
1278
+ # raises in this resolver.
1279
+
1280
+
1281
+ def _capability_env(*, multi_turn=False, is_tool_env=False, images=False):
1282
+ """a minimal single-turn text env, optionally flipped to a shape verl grpo rejects."""
1283
+
1284
+ class _Env:
1285
+ def __init__(self):
1286
+ self.multi_turn = multi_turn
1287
+ self.is_tool_env = is_tool_env
1288
+
1289
+ def dataset(self):
1290
+ return [{"index": i} for i in range(8)]
1291
+
1292
+ def prompt_messages(self, ex):
1293
+ if images:
1294
+ # record_has_images matches an image content BLOCK, so build the real shape rather
1295
+ # than a sentinel key the guard would not see.
1296
+ return [
1297
+ {
1298
+ "role": "user",
1299
+ "content": [
1300
+ {"type": "text", "text": f"question {ex['index']}"},
1301
+ {"type": "image_url", "image_url": {"url": "https://x/y.png"}},
1302
+ ],
1303
+ }
1304
+ ]
1305
+ return [{"role": "user", "content": f"question {ex['index']}"}]
1306
+
1307
+ return _Env()
1308
+
1309
+
1310
+ def _capability_resolve(monkeypatch, env, train=None, overrides=None):
1311
+ """run the resolver against one env, with everything else on the supported path."""
1312
+ from flash.engine.worker._pkg import W as _PkgW
1313
+ from flash.spec import JobSpec
1314
+
1315
+ class _Tokenizer:
1316
+ pad_token = None
1317
+ eos_token = "<eos>"
1318
+
1319
+ def apply_chat_template(self, messages, **kwargs):
1320
+ return "prompt"
1321
+
1322
+ def __call__(self, text, **kwargs):
1323
+ return SimpleNamespace(input_ids=[1])
1324
+
1325
+ spec = JobSpec.from_dict(
1326
+ {
1327
+ "model": "Qwen/Qwen3.5-0.8B",
1328
+ "algorithm": "grpo",
1329
+ "train": {"batch_size": 4, "epochs": 1, **(train or {})},
1330
+ }
1331
+ )
1332
+ monkeypatch.setattr(_PkgW, "JOB_SPEC", spec, raising=False)
1333
+ monkeypatch.setattr(_PkgW, "SEED", 42, raising=False)
1334
+ monkeypatch.setattr(_PkgW, "THINKING", False, raising=False)
1335
+ monkeypatch.setattr(_PkgW, "require_active_env", lambda: env, raising=False)
1336
+ monkeypatch.setattr(_PkgW, "grpo_overrides", lambda: dict(overrides or {}), raising=False)
1337
+ monkeypatch.setattr(_PkgW, "grpo_mask_truncated_completions", lambda t: False, raising=False)
1338
+ monkeypatch.setattr(_PkgW, "load_tokenizer", lambda *a, **k: _Tokenizer(), raising=False)
1339
+ monkeypatch.setattr(rl_verl, "seed_training_rngs", lambda seed: None)
1340
+ monkeypatch.setattr(rl_verl, "model_max_position_embeddings", lambda *a, **k: 32768)
1341
+ return rl_verl._resolve_single_turn_inputs()
1342
+
1343
+
1344
+ def test_capability_guard_rejects_multi_turn_env(monkeypatch):
1345
+ # trl grpo drives multi-turn through a rollout func (rl.py select_grpo_trainer); the verl path
1346
+ # has no equivalent, so it must refuse rather than train only the first turn.
1347
+ with pytest.raises(RuntimeError, match="single-turn, non-tool"):
1348
+ _capability_resolve(monkeypatch, _capability_env(multi_turn=True))
1349
+
1350
+
1351
+ def test_capability_guard_rejects_tool_env(monkeypatch):
1352
+ # trl grpo hands tool schemas AND callables to the trainer; verl gets neither, so a tool env
1353
+ # would train against completions that never call a tool.
1354
+ with pytest.raises(RuntimeError, match="single-turn, non-tool"):
1355
+ _capability_resolve(monkeypatch, _capability_env(is_tool_env=True))
1356
+
1357
+
1358
+ def test_capability_guard_rejects_image_prompts(monkeypatch):
1359
+ # this guard runs AFTER prompt_messages is built, so it needs a real image content block, not a
1360
+ # flag. trl selects a multimodal trainer here; verl grpo is text-only and would silently drop
1361
+ # the image, training the model on the caption alone.
1362
+ with pytest.raises(RuntimeError, match="non-multimodal grpo only"):
1363
+ _capability_resolve(monkeypatch, _capability_env(images=True))
1364
+
1365
+
1366
+ def test_capability_guard_rejects_kl_anchored_warm_start(monkeypatch):
1367
+ # verl computes its kl reference with adapters DISABLED, so under init_from_adapter the
1368
+ # reference is the bare base model and the penalty drags the policy away from the sft start -
1369
+ # the opposite of what the knob asks for. must raise until verl can hold a reference adapter.
1370
+ # the kl coefficient arrives through grpo_overrides, so it must go through the helper: patching
1371
+ # it separately gets clobbered by the helper's own patch and the test then fails on the adapter
1372
+ # download instead, passing a bare raises() while proving nothing about this guard.
1373
+ with pytest.raises(RuntimeError, match="kl_penalty_coef"):
1374
+ _capability_resolve(
1375
+ monkeypatch,
1376
+ _capability_env(),
1377
+ train={"init_from_adapter": "org/some-sft-adapter"},
1378
+ overrides={"kl_penalty_coef": 0.1},
1379
+ )
1380
+
1381
+
1382
+ def test_capability_guards_admit_the_supported_single_turn_text_env(monkeypatch):
1383
+ # the control: with none of the four shapes present the resolver must run to completion, so a
1384
+ # guard that fires on every env would fail here instead of passing the four tests above.
1385
+ inp = _capability_resolve(monkeypatch, _capability_env())
1386
+ assert inp["max_prompt_len"] > 0