freesolo-flash-dev 1.0.0__tar.gz → 1.0.1__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 (341) hide show
  1. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/PKG-INFO +1 -1
  2. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/catalog.py +25 -6
  3. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/commands.py +17 -13
  4. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/client/http.py +2 -2
  5. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/opd_vllm.py +8 -1
  6. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/runner/__init__.py +2 -2
  7. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/schema/__init__.py +9 -1
  8. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/serve/export.py +147 -4
  9. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/_deps.py +9 -13
  10. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/repo_cleanup.py +23 -0
  11. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/routes/runs.py +18 -3
  12. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/pyproject.toml +2 -2
  13. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_catalog_consistency.py +30 -8
  14. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_commands.py +21 -1
  15. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_estimate.py +24 -0
  16. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_client.py +2 -2
  17. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_export.py +363 -0
  18. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_jobs.py +7 -3
  19. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_opd.py +45 -0
  20. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_opd_vllm.py +67 -0
  21. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_server_api.py +120 -7
  22. freesolo_flash_dev-1.0.1/tests/test_serving_context_preflight.py +39 -0
  23. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_train_context_preflight.py +6 -6
  24. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_warmstart_cross_repo.py +2 -2
  25. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/uv.lock +1 -1
  26. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.claude/skills/verify/SKILL.md +0 -0
  27. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.dockerignore +0 -0
  28. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.env.example +0 -0
  29. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/auto-rebake.yml +0 -0
  30. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/bake-kernel-cache.yml +0 -0
  31. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/ci.yml +0 -0
  32. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/main-source-guard.yml +0 -0
  33. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/notify-tests-repo.yml +0 -0
  34. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/publish-dev.yml +0 -0
  35. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/publish-image.yml +0 -0
  36. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/publish.yml +0 -0
  37. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/version-parity.yml +0 -0
  38. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.github/workflows/worker-image.yml +0 -0
  39. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/.gitignore +0 -0
  40. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/Dockerfile +0 -0
  41. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/Dockerfile.worker +0 -0
  42. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/LICENSE +0 -0
  43. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/README.md +0 -0
  44. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/build/kernel_cache/.gitignore +0 -0
  45. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/build/kernel_cache/.keep +0 -0
  46. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/docker/Dockerfile.kernelcache +0 -0
  47. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/docker/Dockerfile.kernelcache.relayer +0 -0
  48. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/docker/bake_kernel_cache.py +0 -0
  49. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/docker/bake_pod_entry.py +0 -0
  50. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/docker/kernel_fingerprint.py +0 -0
  51. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/docker/make_rp_handler.py +0 -0
  52. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/__init__.py +0 -0
  53. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/_channel.py +0 -0
  54. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/_fileio.py +0 -0
  55. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/_logging.py +0 -0
  56. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/_update_check.py +0 -0
  57. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/adapter_artifacts.py +0 -0
  58. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/__init__.py +0 -0
  59. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/__main__.py +0 -0
  60. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/_tty.py +0 -0
  61. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/env_setup.py +0 -0
  62. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/envpush.py +0 -0
  63. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/render.py +0 -0
  64. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cli/training_doc.py +0 -0
  65. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/client/__init__.py +0 -0
  66. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/client/config.py +0 -0
  67. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/client/runtime_secrets.py +0 -0
  68. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/client/specs.py +0 -0
  69. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cost/__init__.py +0 -0
  70. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cost/analytical.py +0 -0
  71. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cost/facts.py +0 -0
  72. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cost/spec.py +0 -0
  73. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/cost/types.py +0 -0
  74. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/diagnostics.py +0 -0
  75. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/__init__.py +0 -0
  76. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/accounting.py +0 -0
  77. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/chalk_kernels.py +0 -0
  78. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/multiturn_rollout.py +0 -0
  79. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/recipe.py +0 -0
  80. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/steps.py +0 -0
  81. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/structured_outputs.py +0 -0
  82. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/vram.py +0 -0
  83. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/__init__.py +0 -0
  84. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/__main__.py +0 -0
  85. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/_pkg.py +0 -0
  86. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/adapter.py +0 -0
  87. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/decoding.py +0 -0
  88. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/finalize.py +0 -0
  89. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/gpu_setup.py +0 -0
  90. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/grpo.py +0 -0
  91. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/heartbeat.py +0 -0
  92. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/hf.py +0 -0
  93. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/kernel_warmup.py +0 -0
  94. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/lora.py +0 -0
  95. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/opd.py +0 -0
  96. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/opd_gkd.py +0 -0
  97. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/packing.py +0 -0
  98. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/perf/__init__.py +0 -0
  99. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/perf/attn.py +0 -0
  100. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/perf/diagnostics.py +0 -0
  101. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/perf/lifecycle.py +0 -0
  102. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/perf/liger.py +0 -0
  103. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/perf/loraplus.py +0 -0
  104. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/perf/memory.py +0 -0
  105. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/rl.py +0 -0
  106. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/rng.py +0 -0
  107. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/sft.py +0 -0
  108. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/teacher.py +0 -0
  109. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/tokenizer_align.py +0 -0
  110. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker/wandb_log.py +0 -0
  111. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/engine/worker_entrypoint.py +0 -0
  112. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/__init__.py +0 -0
  113. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/adapter.py +0 -0
  114. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/archive.py +0 -0
  115. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/archive_policy.py +0 -0
  116. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/base.py +0 -0
  117. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/loader.py +0 -0
  118. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/pull.py +0 -0
  119. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/envs/registry.py +0 -0
  120. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/lora_rank.py +0 -0
  121. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/opd_retry_contract.py +0 -0
  122. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/__init__.py +0 -0
  123. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_auth.py +0 -0
  124. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_deadline.py +0 -0
  125. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_hf_artifacts.py +0 -0
  126. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_hf_retry.py +0 -0
  127. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_http.py +0 -0
  128. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_instance.py +0 -0
  129. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_instance_bootstrap.py +0 -0
  130. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_instance_poll.py +0 -0
  131. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_instance_provider.py +0 -0
  132. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_poll.py +0 -0
  133. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/_worker.py +0 -0
  134. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/allocator.py +0 -0
  135. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/base.py +0 -0
  136. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/__init__.py +0 -0
  137. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/api.py +0 -0
  138. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/auth.py +0 -0
  139. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/gpus.py +0 -0
  140. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
  141. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/jobs/builders.py +0 -0
  142. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/preflight.py +0 -0
  143. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/lambdalabs/pricing.py +0 -0
  144. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/preflight.py +0 -0
  145. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/realized.py +0 -0
  146. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/__init__.py +0 -0
  147. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/api.py +0 -0
  148. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/auth.py +0 -0
  149. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/cost.py +0 -0
  150. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/gpus.py +0 -0
  151. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/jobs.py +0 -0
  152. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/keys.py +0 -0
  153. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/preflight.py +0 -0
  154. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/preload.py +0 -0
  155. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/pricing.py +0 -0
  156. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/slots.py +0 -0
  157. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/train/__init__.py +0 -0
  158. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/runpod/train/endpoints.py +0 -0
  159. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/vast/__init__.py +0 -0
  160. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/vast/api.py +0 -0
  161. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/vast/auth.py +0 -0
  162. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/vast/jobs/__init__.py +0 -0
  163. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/vast/jobs/builders.py +0 -0
  164. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/vast/preflight.py +0 -0
  165. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/providers/vast/pricing.py +0 -0
  166. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/py.typed +0 -0
  167. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/runner/checkpoints.py +0 -0
  168. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/runner/deploy.py +0 -0
  169. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/runner/lifecycle.py +0 -0
  170. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/runner/verified_revisions.py +0 -0
  171. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/schema/fields.py +0 -0
  172. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/serve/__init__.py +0 -0
  173. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/serve/deploy.py +0 -0
  174. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/serve/pricing.py +0 -0
  175. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/serve/urls.py +0 -0
  176. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/__init__.py +0 -0
  177. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/__main__.py +0 -0
  178. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/_internal_client.py +0 -0
  179. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/_locks.py +0 -0
  180. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/_runtime.py +0 -0
  181. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/app.py +0 -0
  182. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/auth.py +0 -0
  183. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/billing.py +0 -0
  184. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/billing_retry.py +0 -0
  185. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/checkpoints.py +0 -0
  186. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/db.py +0 -0
  187. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/environment_registry.py +0 -0
  188. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/envs.py +0 -0
  189. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/reconcile.py +0 -0
  190. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/routes/__init__.py +0 -0
  191. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/routes/envs.py +0 -0
  192. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/routes/meta.py +0 -0
  193. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/routes/serving.py +0 -0
  194. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/server/run_registry.py +0 -0
  195. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/flash/spec.py +0 -0
  196. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/infisical-entrypoint.sh +0 -0
  197. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/scripts/build_dev_dist.py +0 -0
  198. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/__init__.py +0 -0
  199. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/_helpers/__init__.py +0 -0
  200. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/_helpers/runner.py +0 -0
  201. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/_helpers/specs.py +0 -0
  202. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/_helpers/vast.py +0 -0
  203. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/conftest.py +0 -0
  204. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/fixtures/math_eval.jsonl +0 -0
  205. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/fixtures/math_train.jsonl +0 -0
  206. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/live/__init__.py +0 -0
  207. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/live/conftest.py +0 -0
  208. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/live/test_lambda_live.py +0 -0
  209. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/live/test_runpod_live.py +0 -0
  210. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/live/test_vast_live.py +0 -0
  211. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_accounting_coverage.py +0 -0
  212. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_agent_flash_cli_contract.py +0 -0
  213. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_algorithms.py +0 -0
  214. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_allocator.py +0 -0
  215. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_b200_rollout_opt.py +0 -0
  216. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_backend_jobspec_contract.py +0 -0
  217. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_base_model_provenance.py +0 -0
  218. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_billing_retry.py +0 -0
  219. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cancel_remote.py +0 -0
  220. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_chalk_kernels.py +0 -0
  221. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_charge_pricing.py +0 -0
  222. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_checkpoints.py +0 -0
  223. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_commands_coverage.py +0 -0
  224. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_errors.py +0 -0
  225. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_help.py +0 -0
  226. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_main_coverage.py +0 -0
  227. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_managed.py +0 -0
  228. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_render_coverage.py +0 -0
  229. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cli_render_theme.py +0 -0
  230. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_client_server_integration.py +0 -0
  231. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_config_overrides.py +0 -0
  232. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_controlled_experiment_repairs.py +0 -0
  233. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cost_analytical.py +0 -0
  234. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cost_equation.py +0 -0
  235. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cost_estimate.py +0 -0
  236. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cost_hardware.py +0 -0
  237. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cost_models.py +0 -0
  238. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_cost_rewards.py +0 -0
  239. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_dev_channel.py +0 -0
  240. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_disk_gb.py +0 -0
  241. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_endpoint_name.py +0 -0
  242. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_cache_evict.py +0 -0
  243. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_delete.py +0 -0
  244. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_download.py +0 -0
  245. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_download_api.py +0 -0
  246. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_no_install.py +0 -0
  247. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_publish.py +0 -0
  248. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_pull.py +0 -0
  249. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_pull_coverage.py +0 -0
  250. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_pull_loader_coverage.py +0 -0
  251. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_pull_managed_control_plane.py +0 -0
  252. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_push.py +0 -0
  253. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_env_rate_limit_resolve.py +0 -0
  254. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_envs_coverage.py +0 -0
  255. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_flash_mvp.py +0 -0
  256. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_flash_worker.py +0 -0
  257. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_flashinfer_cache_dirs.py +0 -0
  258. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_github_urlopen_retry.py +0 -0
  259. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_gpus.py +0 -0
  260. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_grpo_mask_aware.py +0 -0
  261. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_grpo_params.py +0 -0
  262. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_grpo_sleep_gate.py +0 -0
  263. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_health_liveness.py +0 -0
  264. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_hf_retry.py +0 -0
  265. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_idle_endpoint_reaper.py +0 -0
  266. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_instance_bootstrap_coverage.py +0 -0
  267. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_internal_client.py +0 -0
  268. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_kernel_cache.py +0 -0
  269. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_kernel_fingerprint.py +0 -0
  270. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_kv_util.py +0 -0
  271. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_lambda_api_coverage.py +0 -0
  272. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_lambda_runner.py +0 -0
  273. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_logging.py +0 -0
  274. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_login_perms.py +0 -0
  275. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_lora_rank_coverage.py +0 -0
  276. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_lora_rank_preflight.py +0 -0
  277. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_managed_hf_repo.py +0 -0
  278. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_metrics_schema_agent_contract.py +0 -0
  279. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_mig_guard.py +0 -0
  280. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_multiturn_rollout.py +0 -0
  281. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_multiturn_rollout_coverage.py +0 -0
  282. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_multiturn_rollout_records.py +0 -0
  283. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_multiturn_rollout_request_policy.py +0 -0
  284. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_oom_escalate_gpu.py +0 -0
  285. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_opd_full_state_resume.py +0 -0
  286. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_opd_resume_safety.py +0 -0
  287. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_open_model_policy.py +0 -0
  288. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_orchestrator_flash.py +0 -0
  289. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_packing.py +0 -0
  290. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_packing_coverage.py +0 -0
  291. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_poll_helpers.py +0 -0
  292. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_preflight.py +0 -0
  293. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_provider_preflight_coverage.py +0 -0
  294. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_provider_routing.py +0 -0
  295. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_provider_teardown_robustness.py +0 -0
  296. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_providers_symmetry.py +0 -0
  297. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_realized_cost.py +0 -0
  298. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_repo_cleanup.py +0 -0
  299. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_resolve_params_b.py +0 -0
  300. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_resume_on_retry.py +0 -0
  301. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_runmgmt.py +0 -0
  302. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_runpod_api_delete.py +0 -0
  303. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_runpod_key_fingerprint.py +0 -0
  304. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_runpod_key_waterfall.py +0 -0
  305. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_runpod_slots.py +0 -0
  306. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_serve.py +0 -0
  307. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_server_app_coverage.py +0 -0
  308. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_server_billing.py +0 -0
  309. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_server_checkpoints_coverage.py +0 -0
  310. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_server_db.py +0 -0
  311. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_server_envs_coverage.py +0 -0
  312. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_server_locks_coverage.py +0 -0
  313. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_serving_contract.py +0 -0
  314. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_serving_pricing_coverage.py +0 -0
  315. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_serving_schema_coverage.py +0 -0
  316. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_sft_example_selection.py +0 -0
  317. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_sft_gc_off.py +0 -0
  318. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_sft_max_context.py +0 -0
  319. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_spec_and_validation.py +0 -0
  320. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_structured_outputs.py +0 -0
  321. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_thinking_config.py +0 -0
  322. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_training_controls.py +0 -0
  323. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_update_check.py +0 -0
  324. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_vast_api.py +0 -0
  325. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_vast_api_coverage.py +0 -0
  326. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_vast_offers.py +0 -0
  327. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_vast_provider_coverage.py +0 -0
  328. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_vast_runner.py +0 -0
  329. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_verified_revisions.py +0 -0
  330. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_verifiers.py +0 -0
  331. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_version.py +0 -0
  332. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  333. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_wandb_log_coverage.py +0 -0
  334. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_wandb_naming.py +0 -0
  335. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_weight_cache.py +0 -0
  336. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_worker_dryrun.py +0 -0
  337. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_worker_hardexit.py +0 -0
  338. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_worker_image.py +0 -0
  339. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_worker_init_heartbeat.py +0 -0
  340. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/tests/test_worker_stack.py +0 -0
  341. {freesolo_flash_dev-1.0.0 → freesolo_flash_dev-1.0.1}/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.0
3
+ Version: 1.0.1
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
@@ -111,6 +111,8 @@ class ModelInfo:
111
111
  # multimodal-nested config, so the curated values are what actually engage the gate.
112
112
  num_layers: int = 0
113
113
  hidden_size: int = 0
114
+ # vllm hybrid-mamba cache block size in tokens. 0 means the model has no catalogued mamba floor.
115
+ mamba_block_size: int = 0
114
116
 
115
117
  @property
116
118
  def is_moe(self) -> bool:
@@ -124,6 +126,8 @@ class ModelInfo:
124
126
 
125
127
  def to_dict(self) -> dict[str, Any]:
126
128
  data = asdict(self)
129
+ if not data["mamba_block_size"]:
130
+ del data["mamba_block_size"]
127
131
  serving = data["serving"]
128
132
  if serving is None:
129
133
  del data["serving"]
@@ -170,7 +174,7 @@ MODELS: dict[str, ModelInfo] = {
170
174
  serve_model_id=SERVING_FP8_MODEL_REPOS["openbmb/MiniCPM5-1B"],
171
175
  max_loras=16,
172
176
  max_lora_rank=128,
173
- max_model_len=8192,
177
+ max_model_len=32768,
174
178
  ),
175
179
  thinking="hybrid",
176
180
  notes="On-device class SLM (131k ctx); standard Llama architecture.",
@@ -189,7 +193,7 @@ MODELS: dict[str, ModelInfo] = {
189
193
  serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-0.8B"],
190
194
  max_loras=16,
191
195
  max_lora_rank=128,
192
- max_model_len=8192,
196
+ max_model_len=32768,
193
197
  ),
194
198
  thinking="hybrid",
195
199
  notes="Smallest Qwen3.5; cheap smoke/dev runs with the modern arch.",
@@ -208,7 +212,7 @@ MODELS: dict[str, ModelInfo] = {
208
212
  serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-2B"],
209
213
  max_loras=16,
210
214
  max_lora_rank=128,
211
- max_model_len=8192,
215
+ max_model_len=32768,
212
216
  ),
213
217
  thinking="hybrid",
214
218
  ),
@@ -226,7 +230,7 @@ MODELS: dict[str, ModelInfo] = {
226
230
  serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-4B"],
227
231
  max_loras=16,
228
232
  max_lora_rank=64,
229
- max_model_len=8192,
233
+ max_model_len=32768,
230
234
  max_num_seqs=8,
231
235
  gpu_memory_utilization=0.98,
232
236
  ),
@@ -247,11 +251,11 @@ MODELS: dict[str, ModelInfo] = {
247
251
  quant="bf16",
248
252
  recommended_gpu="A100 PCIe",
249
253
  serving=ServingCapacity(
250
- gpu="L4",
254
+ gpu="H100",
251
255
  serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-9B"],
252
256
  max_loras=16,
253
257
  max_lora_rank=64,
254
- max_model_len=8192,
258
+ max_model_len=32768,
255
259
  max_num_seqs=8,
256
260
  gpu_memory_utilization=0.98,
257
261
  ),
@@ -271,6 +275,10 @@ MODELS: dict[str, ModelInfo] = {
271
275
  # layers x 2048 hidden (hybrid GatedDeltaNet + full-attention, 256 experts / 8 active).
272
276
  num_layers=40,
273
277
  hidden_size=2048,
278
+ # vllm 0.19.1 model_executor/models/config.py derives this from the qwen config via
279
+ # mamba_utils.py: the 1,097,728-byte gdn state page needs 1072 fp8 attention tokens
280
+ # after the 16-token backend alignment applied by hybridattentionmambamodelconfig.
281
+ mamba_block_size=1072,
274
282
  vocab_size=248_320,
275
283
  algos=ALGORITHMS,
276
284
  min_vram_gb=141,
@@ -312,6 +320,17 @@ MODELS: dict[str, ModelInfo] = {
312
320
  }
313
321
 
314
322
 
323
+ def opd_mamba_batched_token_floor(
324
+ model_id: str, seq_cap: int, max_num_seqs: int | None
325
+ ) -> int | None:
326
+ """return a mamba floor only when vllm's derived opd scheduler budget is too small."""
327
+ info = MODELS.get(model_id)
328
+ if info is None or info.mamba_block_size <= 0 or max_num_seqs is None:
329
+ return None
330
+ derived_budget = int(max_num_seqs) * int(seq_cap)
331
+ return info.mamba_block_size if derived_budget < info.mamba_block_size else None
332
+
333
+
315
334
  def list_models() -> list[ModelInfo]:
316
335
  return sorted(MODELS.values(), key=lambda m: (m.min_vram_gb, m.id))
317
336
 
@@ -214,6 +214,7 @@ def _cmd_train_cost(args) -> int:
214
214
  Catalog-only and deterministic. SFT cost never imports the environment; it requires a positive
215
215
  [train].max_examples row count instead of guessing or locally counting a dataset."""
216
216
  from flash.cost import estimate_cost
217
+ from flash.lora_rank import preflight_train_context_within_serving
217
218
 
218
219
  spec = spec_from_file(
219
220
  args.config,
@@ -221,6 +222,7 @@ def _cmd_train_cost(args) -> int:
221
222
  overrides=args.overrides,
222
223
  extra_configs=args.extra_configs,
223
224
  )
225
+ preflight_train_context_within_serving(spec)
224
226
  if spec.train.init_from_adapter:
225
227
  # --cost is offline/catalog-only and cannot read the source adapter, so the rank stays at the
226
228
  # local default. Warm starts train and are priced at the SOURCE adapter's authoritative rank
@@ -302,23 +304,24 @@ def cmd_train(args) -> int:
302
304
  )
303
305
  payload = spec_payload(spec, authored_train_keys=authored_train_keys)
304
306
  client = client_from_config()
307
+ client_train_schema = {
308
+ "version": __version__,
309
+ "fields": train_schema_metadata(),
310
+ "authored_keys": sorted(authored_train_keys),
311
+ }
312
+ runtime_secrets = (
313
+ runtime_secrets_from_local_env(args.config, keys=spec.environment.secrets) or None
314
+ )
305
315
  if args.dry_run:
306
- # Dry-run is a faithful server-side preview: the control plane runs the SAME config
307
- # validation and warm-start/serving preflights it would at real submit (serving rank/context
308
- # caps, the continued warm-start rank match, cost quote) and records a state=dry_run run, but
309
- # allocates no GPU and charges nothing. Local runtime secrets aren't sent — the server
310
- # relaxes the required-[environment].secrets check for a preview, so `--dry-run` works before
311
- # prod secrets are wired up. A rejection surfaces as the server's `error: ...` (exit 1),
312
- # exactly as a real submit would.
316
+ # dry-run is a faithful server-side preview: it sends the same declared secrets and runs the
317
+ # same config, warm-start, serving, and cost preflights as a real submit, but allocates no gpu
318
+ # and charges nothing. a rejection surfaces as the server's error with exit status 1.
313
319
  try:
314
320
  status = client.create_run(
315
321
  payload,
322
+ runtime_secrets=runtime_secrets,
316
323
  dry_run=True,
317
- client_train_schema={
318
- "version": __version__,
319
- "fields": train_schema_metadata(),
320
- "authored_keys": sorted(authored_train_keys),
321
- },
324
+ client_train_schema=client_train_schema,
322
325
  )
323
326
  except ApiError as exc:
324
327
  detail = _legacy_train_key_rejection_detail(exc, authored_train_keys)
@@ -338,7 +341,8 @@ def cmd_train(args) -> int:
338
341
  return 0
339
342
  status = client.create_run(
340
343
  payload,
341
- runtime_secrets=runtime_secrets_from_local_env(args.config, keys=spec.environment.secrets),
344
+ runtime_secrets=runtime_secrets,
345
+ client_train_schema=client_train_schema,
342
346
  )
343
347
  run_id = status["run_id"]
344
348
  logger.info(
@@ -343,8 +343,8 @@ class ApiClient:
343
343
  # Server-side preview: runs the same validation/preflights as a real submit and records a
344
344
  # state=dry_run run, but allocates no GPU and charges nothing. Returns that status.
345
345
  body["dry_run"] = True
346
- if client_train_schema is not None:
347
- body["client_train_schema"] = client_train_schema
346
+ if client_train_schema is not None:
347
+ body["client_train_schema"] = client_train_schema
348
348
  return self._request("POST", "/v1/runs", body=body)
349
349
 
350
350
  def list_runs(self) -> list[dict]:
@@ -127,7 +127,8 @@ def opd_vllm_kwargs(model_id: str, knobs: Any, seq_cap: int) -> dict[str, Any]:
127
127
 
128
128
  fp8_kv = bool(cc >= (8, 9))
129
129
  kwargs["kv_cache_dtype"] = "fp8" if fp8_kv else None
130
- kwargs["max_num_batched_tokens"] = max(8192, int(seq_cap)) if card_gb >= 140 else None
130
+ if card_gb >= 140:
131
+ kwargs["max_num_batched_tokens"] = max(8192, int(seq_cap))
131
132
 
132
133
  if card_gb > 0:
133
134
  try:
@@ -189,6 +190,12 @@ def opd_vllm_kwargs(model_id: str, knobs: Any, seq_cap: int) -> dict[str, Any]:
189
190
  kwargs["rollout_batch_size"] = rollout_concurrency
190
191
  except Exception as exc:
191
192
  print(f"[opd] vLLM memory-util sizing failed; using 0.10: {exc}")
193
+ if card_gb < 140:
194
+ from flash.catalog import opd_mamba_batched_token_floor
195
+
196
+ kwargs["max_num_batched_tokens"] = opd_mamba_batched_token_floor(
197
+ model_id, seq_cap, kwargs["max_num_seqs"]
198
+ )
192
199
  if startup_oom is not None:
193
200
  raise startup_oom
194
201
 
@@ -691,7 +691,7 @@ def _prepare_init_from_adapter(
691
691
  owner_key_id: int | None = None,
692
692
  token: str | None = None,
693
693
  ) -> tuple[JobSpec, JobSpec, dict | None]:
694
- """Preserve the public request while applying source metadata only to the worker spec."""
694
+ """prepare public and worker specs with source-authoritative adapter metadata."""
695
695
  _require_supported_adapter_continuation(spec)
696
696
  ref = spec.train.init_from_adapter
697
697
  if not ref:
@@ -776,7 +776,7 @@ def _prepare_init_from_adapter(
776
776
  )
777
777
  assert metadata is not None
778
778
  identity = adapter_artifact_identity(storage, config, token, revision).to_dict()
779
- public_spec = spec
779
+ public_spec = replace(spec, train=replace(spec.train, lora_alpha=metadata.alpha))
780
780
  worker_spec = replace(
781
781
  worker_spec,
782
782
  train=replace(worker_spec.train, lora_rank=metadata.rank, lora_alpha=metadata.alpha),
@@ -546,7 +546,12 @@ def _validate_grpo(spec: JobSpec) -> None:
546
546
 
547
547
 
548
548
  def _validate_opd(spec: JobSpec) -> None:
549
- """validate that the opd context budget leaves room for a prompt."""
549
+ """validate opd-specific training constraints."""
550
+ if spec.train.kl_penalty_coef == 0.0:
551
+ raise ConfigError(
552
+ "[train] kl_penalty_coef must be > 0 for opd because it scales the gkd "
553
+ "distillation objective; omit it to use the default 1.0 or set a positive value"
554
+ )
550
555
  if spec.train.max_context_tokens:
551
556
  # Mirror run_opd's prompt-budget guard at PARSE time: a context budget that leaves no room
552
557
  # for any prompt after the completion budget is rejected here, BEFORE a paid worker is
@@ -564,6 +569,9 @@ def _validate_opd(spec: JobSpec) -> None:
564
569
  f"invalid budget fails before a GPU worker is provisioned."
565
570
  )
566
571
 
572
+ # short hybrid-mamba contexts are safe because the worker compares vllm's derived scheduler
573
+ # budget with the catalogued block size and supplies an explicit floor only when required.
574
+
567
575
 
568
576
  # Each algorithm's spec-level contract lives in ONE validator, dispatched by name so a new algorithm
569
577
  # adds a function + a map entry rather than another scattered ``if spec.algorithm == ...`` block.
@@ -6,9 +6,12 @@ the destination model repo, so the user never needs access to internal artifact
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import contextlib
9
10
  import json
10
11
  import os
11
12
  import re
13
+ import shutil
14
+ import struct
12
15
  import tempfile
13
16
  from pathlib import Path
14
17
 
@@ -23,6 +26,128 @@ _STALE_ADAPTER_DELETE_PATTERNS = ["adapter_model*", "adapter_config.json"]
23
26
  _TEMP_MERGED_BASE_MODEL_RE = re.compile(
24
27
  r"(?:/[^\s\"'`,\]\){}]+)*/flash_sft_merged_[^\s\"'`,\]\){}]+"
25
28
  )
29
+ _MAX_SAFETENSORS_HEADER_BYTES = 100 * 1024 * 1024
30
+
31
+ # module-path segments outside the language model; mirrors _VL_EXCLUDE_SEGMENTS in
32
+ # flash/engine/worker/lora.py. today's managed adapters never touch these (the worker
33
+ # excludes them from lora), so their presence means a genuinely multimodal adapter whose
34
+ # vision keys the text-only strip cannot represent. normalizing only the lm keys of such
35
+ # an adapter would produce a mixed namespace that matches no transformers class, so the
36
+ # normalization must skip the file entirely and export it as trained.
37
+ _NON_LM_KEY_SEGMENTS = (".visual.", ".vision_tower.", ".multi_modal_projector.", ".mtp.")
38
+
39
+
40
+ def _references_non_lm_modules(key: str) -> bool:
41
+ return any(segment in key for segment in _NON_LM_KEY_SEGMENTS)
42
+
43
+
44
+ def _strip_language_model_infix(key: str) -> str:
45
+ # mirrors _LANGUAGE_MODEL_INFIX namespace semantics in flash/engine/worker/lora.py
46
+ infix = ".language_model."
47
+ index = key.find(infix)
48
+ if index == -1:
49
+ return key
50
+ return key[:index] + "." + key[index + len(infix) :]
51
+
52
+
53
+ def _json_object_without_duplicate_keys(pairs: list[tuple[str, object]]) -> dict[str, object]:
54
+ value: dict[str, object] = {}
55
+ for key, item in pairs:
56
+ if key in value:
57
+ raise ValueError(f"duplicate safetensors JSON key {key!r}")
58
+ value[key] = item
59
+ return value
60
+
61
+
62
+ def _normalize_export_adapter_keys(adapter_dir: Path) -> bool:
63
+ path = adapter_dir / "adapter_model.safetensors"
64
+ if not path.is_file():
65
+ logger.warning("exported adapter has no safetensors weights; leaving weights unchanged")
66
+ return False
67
+
68
+ temp_path: Path | None = None
69
+ try:
70
+ file_size = path.stat().st_size
71
+ with path.open("rb") as source:
72
+ length_bytes = source.read(8)
73
+ if len(length_bytes) != 8:
74
+ raise ValueError("file is too small to contain a safetensors header")
75
+ (header_length,) = struct.unpack("<Q", length_bytes)
76
+ if (
77
+ header_length > file_size - 8
78
+ or header_length > _MAX_SAFETENSORS_HEADER_BYTES
79
+ ):
80
+ raise ValueError(
81
+ f"declared header length {header_length} is implausible for {file_size}-byte file"
82
+ )
83
+ header_bytes = source.read(header_length)
84
+ if len(header_bytes) != header_length:
85
+ raise ValueError("safetensors header is truncated")
86
+ header = json.loads(
87
+ header_bytes,
88
+ object_pairs_hook=_json_object_without_duplicate_keys,
89
+ )
90
+ if not isinstance(header, dict):
91
+ raise ValueError("safetensors header is not a JSON object")
92
+
93
+ non_lm = [
94
+ key
95
+ for key in header
96
+ if key != "__metadata__" and _references_non_lm_modules(key)
97
+ ]
98
+ if non_lm:
99
+ logger.info(
100
+ "exported adapter touches non-lm modules (e.g. %s); keeping the "
101
+ "multimodal key namespace unchanged",
102
+ non_lm[0],
103
+ )
104
+ return False
105
+
106
+ normalized: dict[str, object] = {}
107
+ remapped = 0
108
+ for key, value in header.items():
109
+ normalized_key = (
110
+ key if key == "__metadata__" else _strip_language_model_infix(key)
111
+ )
112
+ if normalized_key in normalized:
113
+ raise ValueError(
114
+ f"key {key!r} collides after stripping the '.language_model.' infix"
115
+ )
116
+ normalized[normalized_key] = value
117
+ remapped += int(normalized_key != key)
118
+ if remapped == 0:
119
+ return False
120
+
121
+ new_header = json.dumps(
122
+ normalized,
123
+ ensure_ascii=False,
124
+ separators=(",", ":"),
125
+ ).encode("utf-8")
126
+ new_header += b" " * (-len(new_header) % 8)
127
+ with tempfile.NamedTemporaryFile(
128
+ mode="wb",
129
+ dir=path.parent,
130
+ prefix=f".{path.name}.",
131
+ delete=False,
132
+ ) as destination:
133
+ temp_path = Path(destination.name)
134
+ destination.write(struct.pack("<Q", len(new_header)))
135
+ destination.write(new_header)
136
+ shutil.copyfileobj(source, destination)
137
+ destination.flush()
138
+ os.fsync(destination.fileno())
139
+ os.replace(temp_path, path)
140
+ temp_path = None
141
+ except Exception as exc:
142
+ logger.warning("could not normalize exported adapter keys; leaving weights unchanged: %s", exc)
143
+ return False
144
+ finally:
145
+ if temp_path is not None:
146
+ with contextlib.suppress(OSError):
147
+ temp_path.unlink(missing_ok=True)
148
+
149
+ logger.info("normalized %d exported adapter weight keys", remapped)
150
+ return True
26
151
 
27
152
 
28
153
  def _rewrite_adapter_config_base_model(
@@ -94,6 +219,23 @@ def _hf_api():
94
219
  return HfApi, snapshot_download
95
220
 
96
221
 
222
+ def _hub_error_types() -> tuple[type[BaseException], ...]:
223
+ error_types: list[type[BaseException]] = []
224
+ try:
225
+ from huggingface_hub.errors import HfHubHTTPError
226
+ except ImportError:
227
+ pass
228
+ else:
229
+ error_types.append(HfHubHTTPError)
230
+ try:
231
+ from requests import RequestException
232
+ except ImportError:
233
+ pass
234
+ else:
235
+ error_types.append(RequestException)
236
+ return tuple(error_types)
237
+
238
+
97
239
  def export_adapter(
98
240
  *,
99
241
  source_repo: str,
@@ -125,9 +267,9 @@ def export_adapter(
125
267
  local_dir=tmp,
126
268
  token=read_token,
127
269
  )
128
- except OSError:
129
- raise
130
270
  except Exception as exc:
271
+ if isinstance(exc, OSError) and not isinstance(exc, _hub_error_types()):
272
+ raise
131
273
  raise ServingError(
132
274
  f"could not download adapter {source_repo}:{source_subfolder}: {exc}"
133
275
  ) from exc
@@ -143,6 +285,7 @@ def export_adapter(
143
285
  "(need adapter_config.json + an adapter_model* weight; nothing to export)"
144
286
  )
145
287
  _repair_export_metadata(adapter_dir, base_model, base_model_revision)
288
+ _normalize_export_adapter_keys(adapter_dir)
146
289
  api = HfApi(token=dest_token)
147
290
  try:
148
291
  # Always create private first so the repo is never transiently exposed empty/partial.
@@ -161,9 +304,9 @@ def export_adapter(
161
304
  )
162
305
  if not private:
163
306
  api.update_repo_settings(repo_id=dest_repo, repo_type="model", private=False)
164
- except OSError:
165
- raise
166
307
  except Exception as exc:
308
+ if isinstance(exc, OSError) and not isinstance(exc, _hub_error_types()):
309
+ raise
167
310
  raise ServingError(f"could not upload adapter to {dest_repo}: {exc}") from exc
168
311
  logger.info(
169
312
  "exported %s:%s -> %s (%d files)", source_repo, source_subfolder, dest_repo, len(files)
@@ -74,9 +74,7 @@ def _parse_spec(payload: dict, run_id: str) -> JobSpec:
74
74
  raise HTTPException(status_code=400, detail=str(exc)) from exc
75
75
 
76
76
 
77
- def _runtime_secrets(
78
- payload: dict, spec: JobSpec, *, require_environment_secrets: bool
79
- ) -> dict[str, str]:
77
+ def _runtime_secrets(payload: dict, spec: JobSpec) -> dict[str, str]:
80
78
  # Use get()+None check, not `or {}` — falsy non-objects must still hit the type check below.
81
79
  raw = payload.get("runtime_secrets")
82
80
  if raw is None:
@@ -102,14 +100,12 @@ def _runtime_secrets(
102
100
  value = value.strip()
103
101
  if value:
104
102
  out[key] = value
105
- if require_environment_secrets:
106
- missing = sorted(set(spec.environment.secrets) - set(out))
107
- if missing:
108
- raise HTTPException(
109
- status_code=400,
110
- detail=(
111
- "missing runtime secret(s) required by [environment] secrets: "
112
- f"{', '.join(missing)}"
113
- ),
114
- )
103
+ missing = sorted(set(spec.environment.secrets) - set(out))
104
+ if missing:
105
+ raise HTTPException(
106
+ status_code=400,
107
+ detail=(
108
+ f"missing runtime secret(s) required by [environment] secrets: {', '.join(missing)}"
109
+ ),
110
+ )
115
111
  return out
@@ -59,6 +59,7 @@ plane with an operator ``HF_TOKEN`` — without it the sweep cannot delete opera
59
59
  from __future__ import annotations
60
60
 
61
61
  import os
62
+ import threading
62
63
  import time
63
64
  from concurrent.futures import ThreadPoolExecutor, as_completed
64
65
  from dataclasses import dataclass
@@ -87,6 +88,26 @@ RUN_REPO_PREFIX = "flashrun-"
87
88
  DELETE_AGE_SECONDS = 7.0 * 86400.0
88
89
  _DELETE_SLEEP_S = 0.5 # pause between deletes — HF repo-mutation rate-limit courtesy
89
90
  _SCAN_WORKERS = 8 # hf tree-listing concurrency
91
+ # ``list_repo_tree(..., expand=True)`` is HF's most expensive listing mode (expand bypasses the
92
+ # CDN and hits origin for a last_commit lookup per entry) -- it rate-limits well below the
93
+ # general API quota. _scan_repo (one call per repo, fanned across _SCAN_WORKERS) and
94
+ # _prefix_written_within (one call per delete target) both hit it; with no shared pacing, the
95
+ # worker pool lets up to _SCAN_WORKERS calls land on HF in the same instant, which is enough on
96
+ # its own to trip the rate limit on a sweep over more than a handful of repos. This floor paces
97
+ # EVERY list_repo_tree call across the whole sweep (not per-thread), so concurrency no longer
98
+ # translates into a request burst.
99
+ _TREE_LIST_MIN_INTERVAL_S = 0.5 # cap ~2 req/s across the whole sweep, workers included
100
+ _tree_list_lock = threading.Lock()
101
+ _tree_list_last_call = 0.0
102
+
103
+
104
+ def _throttle_tree_list() -> None:
105
+ global _tree_list_last_call
106
+ with _tree_list_lock:
107
+ wait = _tree_list_last_call + _TREE_LIST_MIN_INTERVAL_S - time.monotonic()
108
+ if wait > 0:
109
+ time.sleep(wait)
110
+ _tree_list_last_call = time.monotonic()
90
111
 
91
112
  # Only these top-level dirs are deletable model-artifact phases (``JobSpec.phase``: grpo -> "rl",
92
113
  # plus the VL warm-start ``recomb`` recombined adapter). Anything else — ``code/`` snapshots,
@@ -187,6 +208,7 @@ def _scan_repo(api, repo_id: str) -> tuple[dict[str, list], float | None, set[st
187
208
  ``prefixes`` maps ``"<phase>/<run_id>"`` -> ``[total_size, newest_commit_ts]`` for ARTIFACT_PHASES
188
209
  only, ``ref_recent_ts`` is the newest commit among ``referenced_by/`` markers (warm-start-source
189
210
  signal), and ``unknown_tops`` are unrecognized top-level dirs (reported, never deleted)."""
211
+ _throttle_tree_list()
190
212
  entries = api.list_repo_tree(
191
213
  repo_id=repo_id, repo_type="dataset", recursive=True, expand=True
192
214
  )
@@ -246,6 +268,7 @@ def _prefix_written_within(api, repo_id: str, prefix: str, now: float, max_age_s
246
268
  redeploy read-back that landed after enumeration must spare the prefix. Raises on an API error (the
247
269
  caller then skips this target to stay safe). If the listing carries no commit dates (older
248
270
  ``huggingface_hub``), returns ``False`` — the enumeration age gate already qualified it."""
271
+ _throttle_tree_list()
249
272
  entries = api.list_repo_tree(
250
273
  repo_id=repo_id, repo_type="dataset", path_in_repo=prefix, recursive=True, expand=True
251
274
  )
@@ -102,11 +102,11 @@ def _precheck_budget_or_block(*, run_id: str, estimate_usd: float, org_id: str)
102
102
  def create_run(payload: dict, key: Annotated[dict, Depends(require_key)]):
103
103
  dry_run = _require_bool(payload, "dry_run", False)
104
104
  schema = _client_train_schema(payload)
105
+ submitted = payload.get("spec")
106
+ submitted_train = submitted.get("train") if isinstance(submitted, dict) else None
105
107
  try:
106
108
  spec = _parse_spec(payload, run_id=new_run_id())
107
109
  except HTTPException as exc:
108
- submitted = payload.get("spec")
109
- submitted_train = submitted.get("train") if isinstance(submitted, dict) else None
110
110
  server_fields = train_schema_metadata()
111
111
  unsupported = (
112
112
  sorted(
@@ -130,7 +130,7 @@ def create_run(payload: dict, key: Annotated[dict, Depends(require_key)]):
130
130
  )
131
131
  raise HTTPException(status_code=400, detail=detail) from exc
132
132
  raise
133
- runtime_secrets = _runtime_secrets(payload, spec, require_environment_secrets=not dry_run)
133
+ runtime_secrets = _runtime_secrets(payload, spec)
134
134
  affordability_org_id = str(key.get("org_id") or "").strip()
135
135
  bill_on_completion = not dry_run and key.get("auth_kind") != "internal"
136
136
  billing_context = None
@@ -176,6 +176,21 @@ def create_run(payload: dict, key: Annotated[dict, Depends(require_key)]):
176
176
  ),
177
177
  ) from exc
178
178
  raise
179
+ if (
180
+ spec.train.init_from_adapter
181
+ and schema is not None
182
+ and "lora_alpha" in schema["authored_keys"]
183
+ and spec.train.lora_alpha != prepared.worker_spec.train.lora_alpha
184
+ ):
185
+ raise HTTPException(
186
+ status_code=400,
187
+ detail=(
188
+ f"train.lora_alpha={spec.train.lora_alpha} does not match the "
189
+ "train.init_from_adapter source adapter "
190
+ f"lora_alpha={prepared.worker_spec.train.lora_alpha}; omit train.lora_alpha "
191
+ "because source adapter alpha metadata is authoritative"
192
+ ),
193
+ )
179
194
  run_id = prepared.public_spec.run_id
180
195
  if bill_on_completion:
181
196
  _precheck_budget_or_block(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "freesolo-flash-dev"
3
- version = "1.0.0"
3
+ version = "1.0.1"
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).
@@ -113,7 +113,7 @@ artifacts = ["flash/py.typed"]
113
113
  # auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
114
114
  # PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
115
115
  # dev-channel release = bump this (and [project].version) and merge to `dev`.
116
- version = "1.0.0"
116
+ version = "1.0.1"
117
117
 
118
118
  [tool.pytest.ini_options]
119
119
  pythonpath = ["."]