freesolo-flash-dev 0.2.48__tar.gz → 0.2.50__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 (298) hide show
  1. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/PKG-INFO +1 -1
  2. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cli/commands.py +4 -2
  3. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cli/training_doc.py +14 -11
  4. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cost/spec.py +63 -13
  5. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/recipe.py +2 -3
  6. freesolo_flash_dev-0.2.50/flash/engine/steps.py +18 -0
  7. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/grpo.py +0 -13
  8. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/opd.py +366 -140
  9. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/opd_vllm.py +176 -25
  10. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/rl.py +18 -28
  11. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_worker.py +3 -9
  12. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/schema/__init__.py +2 -9
  13. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/spec.py +0 -2
  14. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/pyproject.toml +2 -2
  15. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_agent_flash_cli_contract.py +2 -1
  16. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_algorithms.py +4 -4
  17. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_allocator.py +137 -10
  18. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_backend_jobspec_contract.py +6 -4
  19. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_billing_retry.py +1 -1
  20. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_charge_pricing.py +1 -1
  21. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_checkpoints.py +2 -2
  22. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cli_commands.py +4 -2
  23. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cli_errors.py +5 -3
  24. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cli_estimate.py +29 -13
  25. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cli_managed.py +2 -1
  26. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_client_server_integration.py +1 -1
  27. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_config_overrides.py +9 -5
  28. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_publish.py +1 -1
  29. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_rate_limit_resolve.py +1 -1
  30. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_flash_mvp.py +4 -2
  31. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_flash_worker.py +17 -14
  32. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_gpus.py +3 -2
  33. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_grpo_params.py +18 -17
  34. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_jobs.py +19 -18
  35. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_lora_rank_preflight.py +2 -3
  36. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_opd.py +379 -39
  37. freesolo_flash_dev-0.2.50/tests/test_opd_vllm.py +516 -0
  38. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_orchestrator_flash.py +1 -1
  39. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_runmgmt.py +2 -2
  40. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_server_api.py +13 -13
  41. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_server_billing.py +1 -1
  42. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_spec_and_validation.py +2 -3
  43. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_weight_cache.py +1 -1
  44. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_worker_dryrun.py +13 -0
  45. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/uv.lock +1 -1
  46. freesolo_flash_dev-0.2.48/tests/test_opd_vllm.py +0 -184
  47. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.dockerignore +0 -0
  48. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.env.example +0 -0
  49. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/auto-rebake.yml +0 -0
  50. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/bake-kernel-cache.yml +0 -0
  51. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/ci.yml +0 -0
  52. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/main-source-guard.yml +0 -0
  53. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/notify-tests-repo.yml +0 -0
  54. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/publish-dev.yml +0 -0
  55. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/publish-image.yml +0 -0
  56. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/publish.yml +0 -0
  57. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/version-parity.yml +0 -0
  58. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.github/workflows/worker-image.yml +0 -0
  59. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/.gitignore +0 -0
  60. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/Dockerfile +0 -0
  61. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/Dockerfile.worker +0 -0
  62. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/LICENSE +0 -0
  63. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/README.md +0 -0
  64. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/build/kernel_cache/.gitignore +0 -0
  65. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/build/kernel_cache/.keep +0 -0
  66. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/docker/Dockerfile.kernelcache +0 -0
  67. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/docker/Dockerfile.kernelcache.relayer +0 -0
  68. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/docker/bake_kernel_cache.py +0 -0
  69. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/docker/bake_pod_entry.py +0 -0
  70. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/docker/kernel_fingerprint.py +0 -0
  71. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/docker/make_rp_handler.py +0 -0
  72. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/__init__.py +0 -0
  73. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/_channel.py +0 -0
  74. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/_fileio.py +0 -0
  75. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/_logging.py +0 -0
  76. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/_update_check.py +0 -0
  77. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/adapter_artifacts.py +0 -0
  78. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/catalog.py +0 -0
  79. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cli/__init__.py +0 -0
  80. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cli/__main__.py +0 -0
  81. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cli/_tty.py +0 -0
  82. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cli/envpush.py +0 -0
  83. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cli/render.py +0 -0
  84. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/client/__init__.py +0 -0
  85. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/client/config.py +0 -0
  86. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/client/http.py +0 -0
  87. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/client/runtime_secrets.py +0 -0
  88. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/client/specs.py +0 -0
  89. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cost/__init__.py +0 -0
  90. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cost/analytical.py +0 -0
  91. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cost/facts.py +0 -0
  92. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/cost/types.py +0 -0
  93. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/__init__.py +0 -0
  94. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/accounting.py +0 -0
  95. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/chalk_kernels.py +0 -0
  96. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/multiturn_rollout.py +0 -0
  97. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/vram.py +0 -0
  98. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/__init__.py +0 -0
  99. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/__main__.py +0 -0
  100. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/_pkg.py +0 -0
  101. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/adapter.py +0 -0
  102. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/decoding.py +0 -0
  103. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/finalize.py +0 -0
  104. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/gpu_setup.py +0 -0
  105. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/heartbeat.py +0 -0
  106. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/hf.py +0 -0
  107. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/kernel_warmup.py +0 -0
  108. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/lora.py +0 -0
  109. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/opd_gkd.py +0 -0
  110. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/packing.py +0 -0
  111. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/perf/__init__.py +0 -0
  112. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/perf/attn.py +0 -0
  113. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/perf/diagnostics.py +0 -0
  114. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/perf/lifecycle.py +0 -0
  115. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/perf/liger.py +0 -0
  116. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/perf/loraplus.py +0 -0
  117. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/perf/memory.py +0 -0
  118. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/sft.py +0 -0
  119. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/teacher.py +0 -0
  120. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/tokenizer_align.py +0 -0
  121. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/engine/worker/wandb_log.py +0 -0
  122. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/envs/__init__.py +0 -0
  123. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/envs/adapter.py +0 -0
  124. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/envs/archive_policy.py +0 -0
  125. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/envs/base.py +0 -0
  126. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/envs/loader.py +0 -0
  127. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/envs/pull.py +0 -0
  128. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/envs/registry.py +0 -0
  129. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/lora_rank.py +0 -0
  130. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/__init__.py +0 -0
  131. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_auth.py +0 -0
  132. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_hf_artifacts.py +0 -0
  133. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_hf_retry.py +0 -0
  134. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_http.py +0 -0
  135. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_instance.py +0 -0
  136. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_instance_bootstrap.py +0 -0
  137. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_instance_poll.py +0 -0
  138. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_instance_provider.py +0 -0
  139. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/_poll.py +0 -0
  140. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/allocator.py +0 -0
  141. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/base.py +0 -0
  142. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/__init__.py +0 -0
  143. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/api.py +0 -0
  144. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/auth.py +0 -0
  145. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/gpus.py +0 -0
  146. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
  147. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/jobs/builders.py +0 -0
  148. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/preflight.py +0 -0
  149. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/lambdalabs/pricing.py +0 -0
  150. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/preflight.py +0 -0
  151. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/realized.py +0 -0
  152. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/__init__.py +0 -0
  153. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/api.py +0 -0
  154. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/auth.py +0 -0
  155. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/cost.py +0 -0
  156. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/gpus.py +0 -0
  157. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/jobs.py +0 -0
  158. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/keys.py +0 -0
  159. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/preflight.py +0 -0
  160. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/preload.py +0 -0
  161. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/pricing.py +0 -0
  162. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/slots.py +0 -0
  163. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/train/__init__.py +0 -0
  164. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/train/deps.py +0 -0
  165. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/runpod/train/endpoints.py +0 -0
  166. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/vast/__init__.py +0 -0
  167. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/vast/api.py +0 -0
  168. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/vast/auth.py +0 -0
  169. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/vast/jobs/__init__.py +0 -0
  170. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/vast/jobs/builders.py +0 -0
  171. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/vast/preflight.py +0 -0
  172. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/providers/vast/pricing.py +0 -0
  173. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/py.typed +0 -0
  174. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/runner/__init__.py +0 -0
  175. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/runner/checkpoints.py +0 -0
  176. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/runner/deploy.py +0 -0
  177. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/runner/lifecycle.py +0 -0
  178. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/schema/fields.py +0 -0
  179. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/serve/__init__.py +0 -0
  180. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/serve/deploy.py +0 -0
  181. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/serve/export.py +0 -0
  182. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/serve/pricing.py +0 -0
  183. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/__init__.py +0 -0
  184. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/__main__.py +0 -0
  185. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/_deps.py +0 -0
  186. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/_internal_client.py +0 -0
  187. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/_locks.py +0 -0
  188. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/_runtime.py +0 -0
  189. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/app.py +0 -0
  190. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/auth.py +0 -0
  191. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/billing.py +0 -0
  192. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/billing_retry.py +0 -0
  193. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/checkpoints.py +0 -0
  194. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/db.py +0 -0
  195. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/environment_registry.py +0 -0
  196. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/envs.py +0 -0
  197. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/reconcile.py +0 -0
  198. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/routes/__init__.py +0 -0
  199. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/routes/envs.py +0 -0
  200. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/routes/meta.py +0 -0
  201. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/routes/runs.py +0 -0
  202. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/routes/serving.py +0 -0
  203. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/flash/server/run_registry.py +0 -0
  204. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/infisical-entrypoint.sh +0 -0
  205. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/scripts/build_dev_dist.py +0 -0
  206. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/__init__.py +0 -0
  207. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/_helpers/__init__.py +0 -0
  208. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/_helpers/runner.py +0 -0
  209. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/_helpers/specs.py +0 -0
  210. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/_helpers/vast.py +0 -0
  211. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/conftest.py +0 -0
  212. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/fixtures/math_eval.jsonl +0 -0
  213. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/fixtures/math_train.jsonl +0 -0
  214. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/live/__init__.py +0 -0
  215. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/live/conftest.py +0 -0
  216. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/live/test_lambda_live.py +0 -0
  217. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/live/test_runpod_live.py +0 -0
  218. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/live/test_vast_live.py +0 -0
  219. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_b200_rollout_opt.py +0 -0
  220. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cancel_remote.py +0 -0
  221. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_catalog_consistency.py +0 -0
  222. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_chalk_kernels.py +0 -0
  223. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cli_help.py +0 -0
  224. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cli_render_theme.py +0 -0
  225. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_client.py +0 -0
  226. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cost_analytical.py +0 -0
  227. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cost_equation.py +0 -0
  228. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cost_estimate.py +0 -0
  229. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cost_hardware.py +0 -0
  230. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cost_models.py +0 -0
  231. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_cost_rewards.py +0 -0
  232. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_dev_channel.py +0 -0
  233. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_disk_gb.py +0 -0
  234. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_endpoint_name.py +0 -0
  235. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_cache_evict.py +0 -0
  236. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_delete.py +0 -0
  237. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_download.py +0 -0
  238. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_download_api.py +0 -0
  239. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_no_install.py +0 -0
  240. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_pull.py +0 -0
  241. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_pull_managed_control_plane.py +0 -0
  242. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_env_push.py +0 -0
  243. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_envs_coverage.py +0 -0
  244. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_export.py +0 -0
  245. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_flashinfer_cache_dirs.py +0 -0
  246. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_github_urlopen_retry.py +0 -0
  247. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_grpo_mask_aware.py +0 -0
  248. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_grpo_sleep_gate.py +0 -0
  249. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_health_liveness.py +0 -0
  250. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_idle_endpoint_reaper.py +0 -0
  251. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_internal_client.py +0 -0
  252. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_kernel_cache.py +0 -0
  253. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_kernel_fingerprint.py +0 -0
  254. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_kv_util.py +0 -0
  255. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_lambda_runner.py +0 -0
  256. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_logging.py +0 -0
  257. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_login_perms.py +0 -0
  258. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_managed_hf_repo.py +0 -0
  259. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_metrics_schema_agent_contract.py +0 -0
  260. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_mig_guard.py +0 -0
  261. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_multiturn_rollout.py +0 -0
  262. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_oom_escalate_gpu.py +0 -0
  263. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_open_model_policy.py +0 -0
  264. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_packing.py +0 -0
  265. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_poll_helpers.py +0 -0
  266. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_preflight.py +0 -0
  267. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_provider_routing.py +0 -0
  268. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_provider_teardown_robustness.py +0 -0
  269. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_providers_symmetry.py +0 -0
  270. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_realized_cost.py +0 -0
  271. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_resolve_params_b.py +0 -0
  272. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_resume_on_retry.py +0 -0
  273. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_runpod_api_delete.py +0 -0
  274. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_runpod_key_fingerprint.py +0 -0
  275. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_runpod_key_waterfall.py +0 -0
  276. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_runpod_slots.py +0 -0
  277. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_serve.py +0 -0
  278. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_server_db.py +0 -0
  279. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_serving_contract.py +0 -0
  280. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_sft_example_selection.py +0 -0
  281. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_sft_gc_off.py +0 -0
  282. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_thinking_config.py +0 -0
  283. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_train_context_preflight.py +0 -0
  284. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_update_check.py +0 -0
  285. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_vast_api.py +0 -0
  286. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_vast_offers.py +0 -0
  287. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_vast_runner.py +0 -0
  288. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_verifiers.py +0 -0
  289. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_version.py +0 -0
  290. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  291. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_vl_warmstart_recombine.py +0 -0
  292. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_wandb_naming.py +0 -0
  293. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_warmstart_cross_repo.py +0 -0
  294. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_worker_hardexit.py +0 -0
  295. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_worker_image.py +0 -0
  296. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_worker_init_heartbeat.py +0 -0
  297. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/tests/test_worker_stack.py +0 -0
  298. {freesolo_flash_dev-0.2.48 → freesolo_flash_dev-0.2.50}/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: 0.2.48
3
+ Version: 0.2.50
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
@@ -469,7 +469,8 @@ def cmd_env_setup(args) -> int:
469
469
  "\n"
470
470
  f"{env_comment}"
471
471
  "[train]\n"
472
- "steps = 150\n"
472
+ "epochs = 1\n"
473
+ "max_examples = 2 # rows to train on; the starter dataset has 2 (raise as your dataset grows)\n"
473
474
  f"{rl_reasoning_train}"
474
475
  "lora_rank = 32\n"
475
476
  "# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
@@ -511,7 +512,8 @@ def cmd_env_setup(args) -> int:
511
512
  "[environment]\n"
512
513
  'id = ""\n\n'
513
514
  "[train]\n"
514
- "steps = 100 # opd is step-driven (like GRPO)\n"
515
+ "epochs = 1\n"
516
+ "max_examples = 2 # rows to train on; the starter dataset has 2 (raise as your dataset grows)\n"
515
517
  "lora_rank = 32\n"
516
518
  "# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
517
519
  "# the cheapest fitting managed class, and artifacts live in a private environment-scoped repo.\n"
@@ -103,7 +103,7 @@ id = "your-org/my-env" # the id printed by `flash env push`
103
103
  # never stored in the spec
104
104
 
105
105
  [train]
106
- epochs = 1 # SFT is epoch-driven; GRPO is step-driven (steps = N)
106
+ epochs = 1 # one pass over the retained train rows
107
107
  max_examples = 2 # rows to train on (the starter dataset has 2)
108
108
  lora_rank = 32
109
109
  lora_alpha = 64
@@ -114,7 +114,7 @@ GPU and HF artifacts are **fully managed** — do not pick `gpu.type` or set
114
114
  `train.hf_repo`; the allocator picks the cheapest validated managed GPU class that fits,
115
115
  and run artifacts are stored in a private environment-scoped repo with content-addressed
116
116
  Flash code snapshots. Compose or tweak configs without editing files: `--config
117
- extra.toml` (deep-merge) and `--set key=value` (e.g. `--set train.steps=300`).
117
+ extra.toml` (deep-merge) and `--set key=value` (e.g. `--set train.epochs=3`).
118
118
 
119
119
  ### 4. Submit
120
120
 
@@ -201,7 +201,7 @@ spending another GPU run:
201
201
  | --- | --- | --- |
202
202
  | Environment id is blank or stale | `flash train --dry-run` fails, or the worker uses old reward/data | Run `flash env push --name my-env .` after every environment/data edit and paste the returned id into every config you submit. |
203
203
  | Local-only env path in config | Config validation says there is no local path mode | Publish first, then use the returned slug in `[environment] id`. `flash train` only runs published env ids, not local paths. |
204
- | Config knobs are in the wrong table | Validation rejects `[grpo]`, `[sft]`, or unknown `[train]` keys | Put `steps`, `epochs`, `group_size`, `max_completion_tokens`, `temperature`, `max_context_tokens`, LoRA, and other training knobs under `[train]`. |
204
+ | Config knobs are in the wrong table | Validation rejects `[grpo]`, `[sft]`, or unknown `[train]` keys | Put `epochs`, `group_size`, `max_completion_tokens`, `temperature`, `max_context_tokens`, LoRA, and other training knobs under `[train]`. |
205
205
  | Trying to pin managed infrastructure | `gpu.type`, `train.hf_repo`, or `model_policy` changes do not do what you expected | Treat GPU choice, model policy, and the run artifact repo as managed. Tune the model, algorithm, environment, and `[train]` knobs instead. |
206
206
  | Secrets are not available on the worker | Reward code works locally but remote logs show missing API keys or auth failures | List secret names under `[environment] secrets = [...]`, export those env vars locally before submit, or put them in local `.env` / `.env.local`. Never put secret values in `[worker_env]` or hard-code them in the config. |
207
207
  | Wrong model / thinking setting | Config validation fails, or chat behavior does not match the run | Use `flash models`; set `thinking = true` only for supported models. Thinking is a training-time/run-level choice and serving preserves that parity, so `flash chat` does not expose an override flag. |
@@ -214,7 +214,7 @@ spending another GPU run:
214
214
  | Final checkpoint regresses | Last step is worse than an earlier checkpoint | Run `flash checkpoints <run-id>`, deploy a specific step with `flash deploy <run-id>/step-N`, and compare with held-out probes before exporting or relying on the final adapter. |
215
215
  | Export fails before upload | CLI says no HuggingFace token | Pass `flash export --api-key hf_...`, or set `HF_TOKEN` in your shell, `.env`, or `.env.local`. Exports are private unless you pass `--public`. |
216
216
  | SFT loss improves but quality does not | Train loss falls while held-out behavior stalls or degrades | Keep a held-out split outside training. Deploy and score that split; if quality drops, reduce epochs or improve data instead of adding more passes. |
217
- | Cost surprises | A quick experiment uses more GPU time than intended | Start with `--dry-run` and `--cost`, cap steps/epochs for smoke tests, and scale only after reward/data wiring is proven. Setup time is reported for observability; customer cost is based on training-loop GPU time. |
217
+ | Cost surprises | A quick experiment uses more GPU time than intended | Start with `--dry-run` and `--cost`, keep `epochs` and `max_examples` small for smoke tests, and scale only after reward/data wiring is proven. Setup time is reported for observability; customer cost is based on training-loop GPU time. |
218
218
 
219
219
  ---
220
220
 
@@ -370,7 +370,9 @@ lora_rank = 16 # for VL warm-starts, SFT rank + GRPO rank must fit the effec
370
370
  lora_alpha = 32
371
371
  ```
372
372
 
373
- SFT is **epoch-driven** (`epochs`); GRPO is **step-driven** (`steps`).
373
+ SFT, GRPO, and OPD all accept **epoch-driven** configs (`epochs`). For GRPO/OPD,
374
+ an epoch is one pass over the retained prompt pool after `max_examples` and prompt-budget filtering;
375
+ optimizer-step counts are derived from those epochs.
374
376
 
375
377
  ---
376
378
 
@@ -379,8 +381,8 @@ SFT is **epoch-driven** (`epochs`); GRPO is **step-driven** (`steps`).
379
381
  Pick distillation when a much stronger **teacher** model can grade your student's work
380
382
  token-by-token. The student samples on-policy (like GRPO), the managed GLM 5.2 teacher scores
381
383
  each of *its own* completions, and a dense per-token loss teaches the student to match the teacher —
382
- far more sample-efficient than reward-based RL and with no reward to design. It is **step-driven**
383
- (`steps`) and produces a LoRA served exactly like SFT.
384
+ far more sample-efficient than reward-based RL and with no reward to design. It supports `epochs`
385
+ like SFT/GRPO and produces a LoRA served exactly like SFT.
384
386
 
385
387
  - **No teacher key or model override to set up.** The GLM 5.2 teacher and its Fireworks key are platform-managed: the
386
388
  service supplies its own key to every opd run, so there is nothing to export or declare — an opd
@@ -412,7 +414,8 @@ algorithm = "opd"
412
414
  id = "your-org/my-env"
413
415
 
414
416
  [train]
415
- steps = 100
417
+ epochs = 1
418
+ max_examples = 2
416
419
  lora_rank = 32
417
420
  # kl_penalty_coef = 1.0 # reverse-KL scale
418
421
  ```
@@ -449,7 +452,7 @@ rollouts score somewhere between all-fail and all-pass — is where GRPO has the
449
452
  signal.
450
453
 
451
454
  - If nearly every prompt is solved (most groups score ~1.0): **increase difficulty** —
452
- harder prompts, tighter format/reward, more steps.
455
+ harder prompts, tighter format/reward, more epochs, or more data.
453
456
  - If nearly nothing is solved (most groups score ~0.0): **decrease difficulty** —
454
457
  easier or few-shot prompts, a more lenient (denser) reward, or warm-start with SFT.
455
458
  - In between: good signal — keep iterating at this difficulty.
@@ -500,8 +503,8 @@ on a beyond-noise improvement.
500
503
 
501
504
  ## Scale the evidence
502
505
 
503
- - **A smoke test is not proof.** A single-digit `steps`, a tiny dataset, or a handful
504
- of rollouts only validates the wiring. Scale `steps` / `epochs`, the dataset size,
506
+ - **A smoke test is not proof.** A single-digit derived step count, a tiny dataset, or a handful
507
+ of rollouts only validates the wiring. Scale `epochs`, the dataset size,
505
508
  and `group_size` to the model and the data you actually have before you trust a
506
509
  result. Don't cite budget alone as the reason for an underpowered run.
507
510
  - **Use the data you have.** Deliberately assign every usable row to training or to a
@@ -10,6 +10,7 @@ import math
10
10
  from flash.catalog import samples_on_policy
11
11
  from flash.cost.analytical import estimate_cost
12
12
  from flash.cost.types import CostEstimate, RunConfig
13
+ from flash.engine.steps import on_policy_steps
13
14
 
14
15
 
15
16
  def _sft_epochs(spec) -> int:
@@ -19,6 +20,14 @@ def _sft_epochs(spec) -> int:
19
20
  return int(t.epochs) if t.epochs is not None else RECIPE.sft.num_epochs
20
21
 
21
22
 
23
+ def _on_policy_epochs(spec) -> int:
24
+ from flash.engine.recipe import RECIPE
25
+
26
+ t = spec.train
27
+ default = RECIPE.rl.num_epochs if spec.algorithm == "grpo" else RECIPE.opd.num_epochs
28
+ return int(t.epochs) if t.epochs is not None else default
29
+
30
+
22
31
  def _sft_seq_len(spec) -> int:
23
32
  from flash.engine.recipe import RECIPE
24
33
 
@@ -41,6 +50,43 @@ def _sft_example_count(spec) -> int:
41
50
  )
42
51
 
43
52
 
53
+ def _on_policy_example_count(spec) -> int:
54
+ t = spec.train
55
+ pinned_examples = int(t.max_examples) if t.max_examples else 0
56
+ if pinned_examples > 0:
57
+ return pinned_examples
58
+ env_examples = _env_max_examples(spec)
59
+ if env_examples > 0:
60
+ return env_examples
61
+ return _on_policy_requested_prompts_per_step(spec)
62
+
63
+
64
+ def _env_max_examples(spec) -> int:
65
+ params = getattr(getattr(spec, "environment", None), "params", {}) or {}
66
+ if not isinstance(params, dict):
67
+ return 0
68
+ try:
69
+ value = int(params.get("max_examples") or 0)
70
+ except (TypeError, ValueError):
71
+ return 0
72
+ return max(0, value)
73
+
74
+
75
+ def _on_policy_requested_prompts_per_step(spec) -> int:
76
+ from flash.engine.recipe import RECIPE
77
+
78
+ t = spec.train
79
+ default = (
80
+ RECIPE.rl.prompts_per_step if spec.algorithm == "grpo" else RECIPE.opd.prompts_per_step
81
+ )
82
+ return max(1, int(t.batch_size) if t.batch_size is not None else default)
83
+
84
+
85
+ def _on_policy_prompts_per_step(spec, examples: int) -> int:
86
+ requested = _on_policy_requested_prompts_per_step(spec)
87
+ return max(1, min(requested, max(1, int(examples))))
88
+
89
+
44
90
  def _sft_realized_batch(spec) -> int:
45
91
  from flash.catalog import vocab_size_for
46
92
  from flash.engine.recipe import RECIPE
@@ -68,22 +114,26 @@ def _sft_steps_from_examples(spec, examples: int, *, apply_cap: bool) -> int:
68
114
 
69
115
 
70
116
  def spec_steps(spec) -> int:
71
- """Per-seed optimizer steps implied by a train spec (mirrors the worker). GRPO: ``train.steps``
72
- (else recipe default). SFT: ``epochs x ceil(num_examples / realized_batch)`` capped by
73
- ``max_steps``, where ``num_examples`` must be pinned by ``max_examples``."""
74
- from flash.engine.recipe import RECIPE
117
+ """Per-seed optimizer steps implied by a train spec (mirrors the worker).
75
118
 
76
- t = spec.train
119
+ SFT: ``epochs x ceil(num_examples / realized_batch)`` capped by ``max_steps``. GRPO/OPD:
120
+ ``epochs`` means passes over ``max_examples`` rows when pinned, otherwise the estimate uses one
121
+ prompt batch per epoch.
122
+ """
77
123
  if spec.algorithm == "grpo":
78
- if t.steps is not None:
79
- return max(1, int(t.steps))
80
- return RECIPE.rl.num_steps
124
+ examples = _on_policy_example_count(spec)
125
+ return on_policy_steps(
126
+ epochs=_on_policy_epochs(spec),
127
+ prompt_count=examples,
128
+ prompts_per_step=_on_policy_prompts_per_step(spec, examples),
129
+ )
81
130
  if spec.algorithm == "opd":
82
- # Step-driven like GRPO (on-policy sampling), NOT example-driven — so a opd quote never
83
- # demands [train].max_examples (the SFT fallback below would raise).
84
- if t.steps is not None:
85
- return max(1, int(t.steps))
86
- return RECIPE.opd.num_steps
131
+ examples = _on_policy_example_count(spec)
132
+ return on_policy_steps(
133
+ epochs=_on_policy_epochs(spec),
134
+ prompt_count=examples,
135
+ prompts_per_step=_on_policy_prompts_per_step(spec, examples),
136
+ )
87
137
  # max_examples is a CAP; 0 (like None) means "no cap" (worker trains the full dataset), so
88
138
  # don't let max_examples=0 price a single step.
89
139
  return _sft_steps_from_examples(spec, _sft_example_count(spec), apply_cap=True)
@@ -40,7 +40,7 @@ class RLConfig:
40
40
  max_completion_len_thinking: int = 1536
41
41
  prompts_per_step: int = 64
42
42
  group_size: int = 8
43
- num_steps: int = 150
43
+ num_epochs: int = 1
44
44
  sampling_temperature: float = 1.0
45
45
  sampling_top_p: float = 1.0
46
46
 
@@ -54,8 +54,6 @@ class OPDConfig:
54
54
  # platform-managed and intentionally not configurable from [train].
55
55
  teacher_model: str = "accounts/fireworks/models/glm-5p2"
56
56
  teacher_base_url: str = "https://api.fireworks.ai/inference/v1"
57
- # OPD is step-driven like GRPO (on-policy sampling), not epoch-driven like SFT.
58
- num_steps: int = 100
59
57
  learning_rate: float = 1e-5
60
58
  max_prompt_len: int = 1024
61
59
  max_completion_len: int = 512
@@ -65,6 +63,7 @@ class OPDConfig:
65
63
  # Student samples per prompt. 1 is enough for a direct KD loss (no group-relative baseline
66
64
  # as in GRPO); raise for more teacher-scored coverage per prompt at higher cost.
67
65
  group_size: int = 1
66
+ num_epochs: int = 1
68
67
  sampling_temperature: float = 1.0
69
68
  sampling_top_p: float = 1.0
70
69
  # Reverse-KL coefficient for the groupwise reverse-KL loss; scales the per-span
@@ -0,0 +1,18 @@
1
+ """Training-step derivation shared by worker and cost-estimate paths."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+
7
+
8
+ def on_policy_steps(
9
+ *,
10
+ epochs: int,
11
+ prompt_count: int,
12
+ prompts_per_step: int,
13
+ ) -> int:
14
+ """Resolve GRPO/OPD optimizer steps from full passes over the retained prompt pool."""
15
+ prompt_count = int(prompt_count)
16
+ if prompt_count <= 0:
17
+ raise ValueError("cannot derive epoch-based steps without at least one retained prompt")
18
+ return max(1, math.ceil(prompt_count * int(epochs) / max(1, int(prompts_per_step))))
@@ -2,8 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import os
6
-
7
5
  from flash.engine.worker._pkg import W as _w
8
6
 
9
7
 
@@ -86,17 +84,6 @@ def rl_per_device_comps(
86
84
  """
87
85
  default = 2 if _w.THINKING else 8
88
86
 
89
- _ovr = os.environ.get("FLASH_RL_PER_DEVICE_COMPS", "").strip()
90
- if _ovr:
91
- try:
92
- forced = int(_ovr)
93
- if forced >= 1:
94
- print(f"rl_per_device_comps: FLASH_RL_PER_DEVICE_COMPS override -> per_device={forced}")
95
- return forced
96
- print(f"rl_per_device_comps: ignoring non-positive FLASH_RL_PER_DEVICE_COMPS={_ovr!r}")
97
- except ValueError:
98
- print(f"rl_per_device_comps: ignoring non-integer FLASH_RL_PER_DEVICE_COMPS={_ovr!r}")
99
-
100
87
  logits_cap = _RL_PER_DEVICE_MAX
101
88
  if completion_len > 0 and not fused_logits:
102
89
  logits_cap = max(1, int(6.0e9 / (max(1, completion_len) * vocab * 4)))