freesolo-flash-dev 0.2.34__tar.gz → 0.2.36__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 (272) hide show
  1. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/Dockerfile.worker +1 -1
  2. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/PKG-INFO +4 -4
  3. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/catalog.py +13 -20
  4. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/__init__.py +17 -14
  5. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/commands.py +99 -47
  6. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/envpush.py +9 -11
  7. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/render.py +22 -6
  8. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/training_doc.py +8 -7
  9. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/http.py +55 -28
  10. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/vram.py +52 -3
  11. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/adapter.py +14 -17
  12. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/hf.py +123 -37
  13. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/__init__.py +0 -4
  14. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/rl.py +3 -3
  15. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/sft.py +1 -1
  16. freesolo_flash_dev-0.2.36/flash/envs/adapter.py +447 -0
  17. freesolo_flash_dev-0.2.34/flash/envs/adapter.py → freesolo_flash_dev-0.2.36/flash/envs/loader.py +98 -399
  18. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/pull.py +1 -1
  19. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/registry.py +1 -1
  20. freesolo_flash_dev-0.2.36/flash/lora_rank.py +193 -0
  21. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/train/deps.py +1 -1
  22. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/train/endpoints.py +64 -29
  23. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/__init__.py +127 -12
  24. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/checkpoints.py +64 -13
  25. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/deploy.py +88 -19
  26. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/schema/__init__.py +60 -5
  27. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/deploy.py +175 -32
  28. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_runtime.py +23 -0
  29. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/app.py +19 -1
  30. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/envs.py +3 -4
  31. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/runs.py +1 -1
  32. freesolo_flash_dev-0.2.36/flash/server/routes/serving.py +643 -0
  33. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/pyproject.toml +6 -6
  34. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/conftest.py +29 -0
  35. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_agent_flash_cli_contract.py +2 -4
  36. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cancel_remote.py +123 -0
  37. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_catalog_consistency.py +18 -24
  38. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_checkpoints.py +167 -2
  39. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_commands.py +98 -15
  40. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_render_theme.py +3 -5
  41. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_client.py +31 -42
  42. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_client_server_integration.py +6 -0
  43. freesolo_flash_dev-0.2.36/tests/test_env_cache_evict.py +70 -0
  44. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_pull.py +1 -1
  45. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_rate_limit_resolve.py +8 -8
  46. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_github_urlopen_retry.py +1 -1
  47. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_gpus.py +18 -0
  48. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_grpo_params.py +55 -109
  49. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_jobs.py +448 -0
  50. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_kv_util.py +8 -0
  51. freesolo_flash_dev-0.2.36/tests/test_lora_rank_preflight.py +97 -0
  52. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_orchestrator_flash.py +3 -0
  53. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_serve.py +52 -11
  54. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_server_api.py +332 -13
  55. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_serving_contract.py +191 -3
  56. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_spec_and_validation.py +6 -6
  57. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_verifiers.py +138 -15
  58. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_vl_warmstart_recombine.py +11 -10
  59. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_warmstart_cross_repo.py +21 -4
  60. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/uv.lock +8 -8
  61. freesolo_flash_dev-0.2.34/flash/server/routes/serving.py +0 -348
  62. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.dockerignore +0 -0
  63. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.env.example +0 -0
  64. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/auto-rebake.yml +0 -0
  65. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/bake-kernel-cache.yml +0 -0
  66. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/ci.yml +0 -0
  67. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/main-source-guard.yml +0 -0
  68. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/notify-tests-repo.yml +0 -0
  69. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/publish-dev.yml +0 -0
  70. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/publish-image.yml +0 -0
  71. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/publish.yml +0 -0
  72. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/version-parity.yml +0 -0
  73. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/worker-image.yml +0 -0
  74. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.gitignore +0 -0
  75. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/Dockerfile +0 -0
  76. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/LICENSE +0 -0
  77. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/README.md +0 -0
  78. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/build/kernel_cache/.gitignore +0 -0
  79. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/build/kernel_cache/.keep +0 -0
  80. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/Dockerfile.kernelcache +0 -0
  81. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/Dockerfile.kernelcache.relayer +0 -0
  82. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/bake_kernel_cache.py +0 -0
  83. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/bake_pod_entry.py +0 -0
  84. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/kernel_fingerprint.py +0 -0
  85. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/make_rp_handler.py +0 -0
  86. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/README.md +0 -0
  87. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/generate.py +0 -0
  88. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/index.html +0 -0
  89. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/preview.png +0 -0
  90. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/themed-errors.png +0 -0
  91. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/kernel-cache.md +0 -0
  92. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/__init__.py +0 -0
  93. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_channel.py +0 -0
  94. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_fileio.py +0 -0
  95. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_logging.py +0 -0
  96. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_update_check.py +0 -0
  97. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/__main__.py +0 -0
  98. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/__init__.py +0 -0
  99. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/config.py +0 -0
  100. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/runtime_secrets.py +0 -0
  101. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/specs.py +0 -0
  102. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/__init__.py +0 -0
  103. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/analytical.py +0 -0
  104. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/facts.py +0 -0
  105. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/spec.py +0 -0
  106. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/types.py +0 -0
  107. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/__init__.py +0 -0
  108. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/accounting.py +0 -0
  109. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/chalk_kernels.py +0 -0
  110. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/multiturn_rollout.py +0 -0
  111. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/recipe.py +0 -0
  112. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/__init__.py +0 -0
  113. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/__main__.py +0 -0
  114. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/_pkg.py +0 -0
  115. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/decoding.py +0 -0
  116. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/finalize.py +0 -0
  117. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/gpu_setup.py +0 -0
  118. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/grpo.py +0 -0
  119. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/heartbeat.py +0 -0
  120. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/kernel_warmup.py +0 -0
  121. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/lora.py +0 -0
  122. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/packing.py +0 -0
  123. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/attn.py +0 -0
  124. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/diagnostics.py +0 -0
  125. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/lifecycle.py +0 -0
  126. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/liger.py +0 -0
  127. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/loraplus.py +0 -0
  128. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/memory.py +0 -0
  129. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/wandb_log.py +0 -0
  130. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/__init__.py +0 -0
  131. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/base.py +0 -0
  132. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/__init__.py +0 -0
  133. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_auth.py +0 -0
  134. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_http.py +0 -0
  135. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_instance.py +0 -0
  136. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_instance_bootstrap.py +0 -0
  137. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_poll.py +0 -0
  138. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/allocator.py +0 -0
  139. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/base.py +0 -0
  140. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/__init__.py +0 -0
  141. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/api.py +0 -0
  142. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/auth.py +0 -0
  143. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/gpus.py +0 -0
  144. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
  145. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/jobs/builders.py +0 -0
  146. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/preflight.py +0 -0
  147. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/pricing.py +0 -0
  148. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/train.py +0 -0
  149. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/preflight.py +0 -0
  150. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/realized.py +0 -0
  151. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/__init__.py +0 -0
  152. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/api.py +0 -0
  153. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/auth.py +0 -0
  154. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/cost.py +0 -0
  155. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/gpus.py +0 -0
  156. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/jobs.py +0 -0
  157. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/keys.py +0 -0
  158. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/preflight.py +0 -0
  159. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/preload.py +0 -0
  160. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/pricing.py +0 -0
  161. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/slots.py +0 -0
  162. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/train/__init__.py +0 -0
  163. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/py.typed +0 -0
  164. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/lifecycle.py +0 -0
  165. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/schema/fields.py +0 -0
  166. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/__init__.py +0 -0
  167. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/export.py +0 -0
  168. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/pricing.py +0 -0
  169. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/__init__.py +0 -0
  170. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/__main__.py +0 -0
  171. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_deps.py +0 -0
  172. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_internal_client.py +0 -0
  173. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_locks.py +0 -0
  174. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/auth.py +0 -0
  175. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/billing.py +0 -0
  176. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/billing_retry.py +0 -0
  177. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/checkpoints.py +0 -0
  178. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/db.py +0 -0
  179. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/environment_registry.py +0 -0
  180. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/reconcile.py +0 -0
  181. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/__init__.py +0 -0
  182. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/envs.py +0 -0
  183. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/meta.py +0 -0
  184. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/run_registry.py +0 -0
  185. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/spec.py +0 -0
  186. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/infisical-entrypoint.sh +0 -0
  187. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/scripts/build_dev_dist.py +0 -0
  188. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/__init__.py +0 -0
  189. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/_helpers/__init__.py +0 -0
  190. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/_helpers/runner.py +0 -0
  191. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/_helpers/specs.py +0 -0
  192. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/fixtures/math_eval.jsonl +0 -0
  193. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/fixtures/math_train.jsonl +0 -0
  194. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/__init__.py +0 -0
  195. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/conftest.py +0 -0
  196. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/test_lambda_live.py +0 -0
  197. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/test_runpod_live.py +0 -0
  198. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_algorithms.py +0 -0
  199. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_allocator.py +0 -0
  200. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_b200_rollout_opt.py +0 -0
  201. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_backend_jobspec_contract.py +0 -0
  202. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_billing_retry.py +0 -0
  203. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_chalk_kernels.py +0 -0
  204. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_charge_pricing.py +0 -0
  205. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_errors.py +0 -0
  206. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_estimate.py +0 -0
  207. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_help.py +0 -0
  208. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_managed.py +0 -0
  209. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_config_overrides.py +0 -0
  210. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_analytical.py +0 -0
  211. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_equation.py +0 -0
  212. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_estimate.py +0 -0
  213. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_hardware.py +0 -0
  214. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_models.py +0 -0
  215. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_rewards.py +0 -0
  216. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_dev_channel.py +0 -0
  217. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_disk_gb.py +0 -0
  218. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_endpoint_name.py +0 -0
  219. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_delete.py +0 -0
  220. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_no_install.py +0 -0
  221. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_publish.py +0 -0
  222. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_push.py +0 -0
  223. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_envs_coverage.py +0 -0
  224. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_export.py +0 -0
  225. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_flash_mvp.py +0 -0
  226. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_flash_worker.py +0 -0
  227. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_flashinfer_cache_dirs.py +0 -0
  228. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_grpo_mask_aware.py +0 -0
  229. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_grpo_sleep_gate.py +0 -0
  230. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_idle_endpoint_reaper.py +0 -0
  231. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_internal_client.py +0 -0
  232. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_kernel_cache.py +0 -0
  233. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_kernel_fingerprint.py +0 -0
  234. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_lambda_runner.py +0 -0
  235. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_logging.py +0 -0
  236. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_login_perms.py +0 -0
  237. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_managed_hf_repo.py +0 -0
  238. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_metrics_schema_agent_contract.py +0 -0
  239. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_mig_guard.py +0 -0
  240. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_multiturn_rollout.py +0 -0
  241. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_oom_escalate_gpu.py +0 -0
  242. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_open_model_policy.py +0 -0
  243. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_packing.py +0 -0
  244. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_poll_helpers.py +0 -0
  245. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_preflight.py +0 -0
  246. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_provider_routing.py +0 -0
  247. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_provider_teardown_robustness.py +0 -0
  248. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_providers_symmetry.py +0 -0
  249. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_realized_cost.py +0 -0
  250. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_resolve_params_b.py +0 -0
  251. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_resume_on_retry.py +0 -0
  252. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runmgmt.py +0 -0
  253. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_api_delete.py +0 -0
  254. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_key_fingerprint.py +0 -0
  255. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_key_waterfall.py +0 -0
  256. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_slots.py +0 -0
  257. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_server_billing.py +0 -0
  258. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_server_db.py +0 -0
  259. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_sft_gc_off.py +0 -0
  260. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_thinking_config.py +0 -0
  261. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_update_check.py +0 -0
  262. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_version.py +0 -0
  263. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  264. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_vl_weight_sync.py +0 -0
  265. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_wandb_naming.py +0 -0
  266. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_weight_cache.py +0 -0
  267. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_dryrun.py +0 -0
  268. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_hardexit.py +0 -0
  269. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_image.py +0 -0
  270. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_init_heartbeat.py +0 -0
  271. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_stack.py +0 -0
  272. {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_thinking.py +0 -0
@@ -63,7 +63,7 @@ RUN pip install --no-cache-dir \
63
63
  "tilelang==0.1.11" \
64
64
  "apache-tvm-ffi==0.1.11" \
65
65
  "hf_transfer" \
66
- "freesolo>=0.2.52" \
66
+ "freesolo>=0.2.54" \
67
67
  "runpod"
68
68
  # Gated-DeltaNet (Qwen3.5/3.6) runs on flash-linear-attention's Triton kernels. On consumer cards
69
69
  # (Ampere/Ada/Blackwell) the Triton path is correct. On Hopper (sm90) fla's GDN chunk_bwd is
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freesolo-flash-dev
3
- Version: 0.2.34
3
+ Version: 0.2.36
4
4
  Summary: Flash — managed LoRA post-training (SFT/GRPO) 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
@@ -18,7 +18,7 @@ Requires-Python: <3.13,>=3.11
18
18
  Provides-Extra: dev
19
19
  Requires-Dist: datasets>=2.19; extra == 'dev'
20
20
  Requires-Dist: fastapi; extra == 'dev'
21
- Requires-Dist: freesolo>=0.2.52; extra == 'dev'
21
+ Requires-Dist: freesolo>=0.2.54; extra == 'dev'
22
22
  Requires-Dist: httpx>=0.27; extra == 'dev'
23
23
  Requires-Dist: huggingface-hub>=0.34; extra == 'dev'
24
24
  Requires-Dist: mypy>=1.13.0; extra == 'dev'
@@ -31,7 +31,7 @@ Provides-Extra: gpu
31
31
  Requires-Dist: accelerate>=1.4; extra == 'gpu'
32
32
  Requires-Dist: bitsandbytes>=0.49; extra == 'gpu'
33
33
  Requires-Dist: datasets>=2.19; extra == 'gpu'
34
- Requires-Dist: freesolo>=0.2.52; extra == 'gpu'
34
+ Requires-Dist: freesolo>=0.2.54; extra == 'gpu'
35
35
  Requires-Dist: huggingface-hub>=0.34; extra == 'gpu'
36
36
  Requires-Dist: peft>=0.19; extra == 'gpu'
37
37
  Requires-Dist: torch==2.10.0; extra == 'gpu'
@@ -41,7 +41,7 @@ Requires-Dist: vllm==0.19.1; extra == 'gpu'
41
41
  Provides-Extra: server
42
42
  Requires-Dist: datasets>=2.19; extra == 'server'
43
43
  Requires-Dist: fastapi; extra == 'server'
44
- Requires-Dist: freesolo>=0.2.52; extra == 'server'
44
+ Requires-Dist: freesolo>=0.2.54; extra == 'server'
45
45
  Requires-Dist: httpx>=0.27; extra == 'server'
46
46
  Requires-Dist: huggingface-hub>=0.34; extra == 'server'
47
47
  Requires-Dist: runpod-flash; extra == 'server'
@@ -116,11 +116,8 @@ class ModelInfo:
116
116
  DEFAULT_MODEL = "Qwen/Qwen3.5-4B"
117
117
 
118
118
  SERVING_FP8_MODEL_REPOS: dict[str, str] = {
119
- "openbmb/MiniCPM5-1B": "Freesolo-Co/MiniCPM5-1B-FP8",
120
- "Qwen/Qwen3.5-0.8B": "Freesolo-Co/Qwen3.5-0.8B-FP8",
121
- "Qwen/Qwen3.5-2B": "Freesolo-Co/Qwen3.5-2B-FP8",
122
- "Qwen/Qwen3.5-4B": "Freesolo-Co/Qwen3.5-4B-FP8",
123
- "Qwen/Qwen3.5-9B": "Freesolo-Co/Qwen3.5-9B-FP8",
119
+ "Qwen/Qwen3.5-4B": "lovedheart/Qwen3.5-4B-FP8",
120
+ "Qwen/Qwen3.5-9B": "lovedheart/Qwen3.5-9B-FP8",
124
121
  "Qwen/Qwen3.6-35B-A3B": "Qwen/Qwen3.6-35B-A3B-FP8",
125
122
  }
126
123
 
@@ -136,9 +133,8 @@ MODELS: dict[str, ModelInfo] = {
136
133
  recommended_gpu="RTX 4090",
137
134
  serving=ServingCapacity(
138
135
  gpu="L4",
139
- serve_model_id=SERVING_FP8_MODEL_REPOS["openbmb/MiniCPM5-1B"],
140
136
  max_loras=16,
141
- max_lora_rank=128,
137
+ max_lora_rank=64,
142
138
  max_model_len=32768,
143
139
  ),
144
140
  thinking="hybrid",
@@ -155,9 +151,8 @@ MODELS: dict[str, ModelInfo] = {
155
151
  recommended_gpu="RTX 4090",
156
152
  serving=ServingCapacity(
157
153
  gpu="L4",
158
- serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-0.8B"],
159
154
  max_loras=16,
160
- max_lora_rank=128,
155
+ max_lora_rank=64,
161
156
  max_model_len=32768,
162
157
  ),
163
158
  thinking="hybrid",
@@ -174,9 +169,8 @@ MODELS: dict[str, ModelInfo] = {
174
169
  recommended_gpu="RTX 4090",
175
170
  serving=ServingCapacity(
176
171
  gpu="L4",
177
- serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-2B"],
178
172
  max_loras=16,
179
- max_lora_rank=128,
173
+ max_lora_rank=64,
180
174
  max_model_len=32768,
181
175
  ),
182
176
  thinking="hybrid",
@@ -191,10 +185,10 @@ MODELS: dict[str, ModelInfo] = {
191
185
  min_vram_gb=32,
192
186
  recommended_gpu="RTX 5090",
193
187
  serving=ServingCapacity(
194
- gpu="L40S",
188
+ gpu="L4",
195
189
  serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-4B"],
196
190
  max_loras=64,
197
- max_lora_rank=64,
191
+ max_lora_rank=32,
198
192
  max_model_len=8192,
199
193
  max_num_seqs=8,
200
194
  gpu_memory_utilization=0.98,
@@ -216,10 +210,10 @@ MODELS: dict[str, ModelInfo] = {
216
210
  quant="bf16",
217
211
  recommended_gpu="A100 PCIe",
218
212
  serving=ServingCapacity(
219
- gpu="L40S",
213
+ gpu="L4",
220
214
  serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.5-9B"],
221
215
  max_loras=44,
222
- max_lora_rank=64,
216
+ max_lora_rank=32,
223
217
  max_model_len=8192,
224
218
  max_num_seqs=8,
225
219
  gpu_memory_utilization=0.98,
@@ -254,14 +248,13 @@ MODELS: dict[str, ModelInfo] = {
254
248
  quant="bf16",
255
249
  recommended_gpu="H200",
256
250
  serving=ServingCapacity(
257
- gpu="A100-80GB:2",
251
+ gpu="A100-80GB",
258
252
  serve_model_id=SERVING_FP8_MODEL_REPOS["Qwen/Qwen3.6-35B-A3B"],
259
253
  max_loras=12,
260
- max_lora_rank=64,
254
+ max_lora_rank=32,
261
255
  max_model_len=8192,
262
256
  max_num_seqs=8,
263
257
  max_num_batched_tokens=4096,
264
- tensor_parallel_size=2,
265
258
  gpu_memory_utilization=0.98,
266
259
  ),
267
260
  thinking="hybrid",
@@ -292,8 +285,8 @@ def get_model(model_id: str) -> ModelInfo:
292
285
  def serving_lora_rank_cap(model: str | ModelInfo | None) -> int | None:
293
286
  """Return the model's serving LoRA rank cap, or None when Flash has no local cap.
294
287
 
295
- Serving capacity is model-specific: small serving models currently allow rank 128, while larger
296
- serving paths currently allow rank 64. Unknown/open-policy models intentionally return None instead
288
+ Serving capacity is model-specific: small serving models currently allow rank 64, while larger
289
+ serving paths currently allow rank 32. Unknown/open-policy models intentionally return None instead
297
290
  of inheriting a global fallback.
298
291
  """
299
292
  if isinstance(model, ModelInfo):
@@ -348,14 +348,17 @@ def _build_parser() -> argparse.ArgumentParser:
348
348
  checkpoints.set_defaults(func=cmd_checkpoints)
349
349
 
350
350
  deploy = sub.add_parser("deploy", help="deploy a run's adapter to a serving endpoint")
351
- deploy.add_argument("run_id")
351
+ deploy.add_argument(
352
+ "run_id",
353
+ metavar="RUN_ID[/step-N]",
354
+ help="run id for the final adapter, or RUN_ID/step-N for a saved checkpoint",
355
+ )
352
356
  deploy.add_argument("--dry-run", action="store_true")
353
357
  deploy.add_argument(
354
- "--step",
355
- type=int,
356
- default=None,
357
- help="deploy a specific intermediate checkpoint (see `flash checkpoints <run_id>`) "
358
- "instead of the run's final adapter; works even for a run cancelled mid-RL",
358
+ "--no-verify",
359
+ action="store_true",
360
+ help="skip the server-side post-deploy smoke generation (registration alone does NOT "
361
+ "guarantee the adapter serves; only ready deployments should be scored by evals)",
359
362
  )
360
363
  deploy.set_defaults(func=cmd_deploy)
361
364
 
@@ -368,7 +371,8 @@ def _build_parser() -> argparse.ArgumentParser:
368
371
  "--adapter-id",
369
372
  dest="adapter_id",
370
373
  required=True,
371
- help="the Freesolo adapter id (the run id) to export",
374
+ metavar="RUN_ID[/step-N]",
375
+ help="run id for the final adapter, or RUN_ID/step-N for a saved checkpoint",
372
376
  )
373
377
  export.add_argument(
374
378
  "--repository",
@@ -380,13 +384,6 @@ def _build_parser() -> argparse.ArgumentParser:
380
384
  help="HuggingFace token with write access to --repository "
381
385
  "(default: HF_TOKEN from your shell or a local .env / .env.local)",
382
386
  )
383
- export.add_argument(
384
- "--step",
385
- type=int,
386
- default=None,
387
- help="export a specific intermediate checkpoint (see `flash checkpoints <adapter-id>`) "
388
- "instead of the run's final adapter; works even for a run cancelled mid-RL",
389
- )
390
387
  export.add_argument(
391
388
  "--public",
392
389
  action="store_true",
@@ -400,6 +397,12 @@ def _build_parser() -> argparse.ArgumentParser:
400
397
  chat = sub.add_parser("chat", help="chat with a deployed adapter")
401
398
  chat.add_argument("run_id")
402
399
  chat.add_argument("-m", "--message", required=True)
400
+ chat.add_argument(
401
+ "--system",
402
+ default=None,
403
+ help="optional system prompt sent ahead of the user message "
404
+ "(training-prompt parity for evals)",
405
+ )
403
406
  chat.add_argument("--max-tokens", type=int, default=512)
404
407
  chat.add_argument("--temperature", type=float, default=0.0)
405
408
  chat.set_defaults(func=cmd_chat)
@@ -407,9 +407,12 @@ def cmd_train(args) -> int:
407
407
  return _follow_run(client, run_id)
408
408
 
409
409
 
410
- def _poll_logs(client: ApiClient, run_id: str, interval: float) -> str:
411
- """Stream offset-paged logs until the run reaches a terminal state; return that state."""
410
+ def _poll_logs(client: ApiClient, run_id: str, interval: float) -> tuple[str, bool]:
411
+ """Stream offset-paged logs until the run reaches a terminal state.
412
+
413
+ Returns (terminal state, whether any log bytes were printed)."""
412
414
  offset = 0
415
+ printed_any = False
413
416
  spinner = _LogFollowSpinner(run_id)
414
417
  try:
415
418
  while True:
@@ -417,23 +420,25 @@ def _poll_logs(client: ApiClient, run_id: str, interval: float) -> str:
417
420
  if page["logs"]:
418
421
  spinner.clear()
419
422
  print(page["logs"], end="", flush=True)
423
+ printed_any = True
420
424
  offset = page["offset"]
421
425
  if page["state"] in _CLI_DONE_STATES:
422
426
  spinner.clear()
423
- return page["state"]
427
+ return page["state"], printed_any
424
428
  _sleep_with_spinner(interval, spinner, page["state"])
425
429
  finally:
426
430
  spinner.clear()
427
431
 
428
432
 
433
+ def _render_status(status: dict) -> str:
434
+ """One rendering of a run status: themed panel on a TTY, indented JSON on the machine path."""
435
+ return render.run_status(status) if render.styled() else json.dumps(status, indent=2)
436
+
437
+
429
438
  def _follow_run(client: ApiClient, run_id: str) -> int:
430
439
  """Poll logs until the run reaches a terminal state, then print the final status."""
431
- state = _poll_logs(client, run_id, interval=2.0)
432
- status = client.get_run(run_id)
433
- if render.styled():
434
- print(render.run_status(status))
435
- else:
436
- print(json.dumps(status, indent=2))
440
+ state, _ = _poll_logs(client, run_id, interval=2.0)
441
+ print(_render_status(client.get_run(run_id)))
437
442
  return 0 if state in _OK_STATES else 1
438
443
 
439
444
 
@@ -442,7 +447,7 @@ def _follow_status(client: ApiClient, run_id: str, interval: float = 2.0) -> int
442
447
  last_rendered: str | None = None
443
448
  while True:
444
449
  status = client.get_run(run_id)
445
- rendered = render.run_status(status) if render.styled() else json.dumps(status, indent=2)
450
+ rendered = _render_status(status)
446
451
  if rendered != last_rendered:
447
452
  print(rendered)
448
453
  last_rendered = rendered
@@ -452,21 +457,6 @@ def _follow_status(client: ApiClient, run_id: str, interval: float = 2.0) -> int
452
457
  time.sleep(interval)
453
458
 
454
459
 
455
- def _print_log_text(text: str) -> bool:
456
- if not text:
457
- return False
458
- print(text, end="")
459
- if not text.endswith("\n"):
460
- print()
461
- return True
462
-
463
-
464
- def _print_log_snapshot(client: ApiClient, run_id: str) -> bool:
465
- """Print a finite snapshot from the log endpoint without following new bytes."""
466
- page = client.get_logs(run_id, offset=0)
467
- return _print_log_text(str(page.get("logs") or ""))
468
-
469
-
470
460
  def _print_worker_output(client: ApiClient, run_id: str, *, printed_any: bool = False) -> bool:
471
461
  for name, text in (client.get_worker_output(run_id) or {}).items():
472
462
  if not text:
@@ -484,11 +474,13 @@ def _print_worker_output(client: ApiClient, run_id: str, *, printed_any: bool =
484
474
  def cmd_log(args) -> int:
485
475
  client = client_from_config()
486
476
  if getattr(args, "follow", False):
487
- state = _poll_logs(client, args.run_id, interval=2.0)
488
- _print_worker_output(client, args.run_id, printed_any=True)
477
+ state, printed_any = _poll_logs(client, args.run_id, interval=2.0)
478
+ _print_worker_output(client, args.run_id, printed_any=printed_any)
489
479
  return 0 if state in _OK_STATES else 1
490
- printed_any = _print_log_snapshot(client, args.run_id)
491
- _print_worker_output(client, args.run_id, printed_any=printed_any)
480
+ text = str(client.get_logs(args.run_id, offset=0).get("logs") or "")
481
+ if text:
482
+ print(text, end="" if text.endswith("\n") else "\n")
483
+ _print_worker_output(client, args.run_id, printed_any=bool(text))
492
484
  return 0
493
485
 
494
486
 
@@ -496,11 +488,7 @@ def cmd_status(args) -> int:
496
488
  client = client_from_config()
497
489
  if getattr(args, "follow", False):
498
490
  return _follow_status(client, args.run_id)
499
- status = client.get_run(args.run_id)
500
- if render.styled():
501
- print(render.run_status(status))
502
- else:
503
- print(json.dumps(status, indent=2))
491
+ print(_render_status(client.get_run(args.run_id)))
504
492
  return 0
505
493
 
506
494
 
@@ -553,20 +541,37 @@ def cmd_checkpoints(args) -> int:
553
541
  if render.styled():
554
542
  print(render.checkpoints_table(args.run_id, checkpoints))
555
543
  return 0
544
+ from flash.schema import format_checkpoint_ref
545
+
556
546
  for c in checkpoints:
557
- print(f"step {c['step']:>6} {c['repo_id']}:{c['subfolder']}")
547
+ # single-space, unpadded columns so a plain `grep "step N"` / awk split works; the ref is
548
+ # the canonical short form, paste-able into train.init_from_adapter.
549
+ print(f"step {c['step']} {format_checkpoint_ref(args.run_id, c['step'])}")
558
550
  print(
559
- f"\ndeploy one with `flash deploy {args.run_id} --step <STEP>`.",
551
+ f"\ndeploy one with `flash deploy {args.run_id}/step-<STEP>`.",
560
552
  file=sys.stderr,
561
553
  )
562
554
  return 0
563
555
 
564
556
 
565
557
  def cmd_deploy(args) -> int:
566
- dep = client_from_config().deploy(
558
+ from flash.schema import parse_checkpoint_ref
559
+
560
+ # `flash deploy <run_id>/step-N` is the same checkpoint ref `flash checkpoints` prints.
561
+ parsed = parse_checkpoint_ref(args.run_id)
562
+ if parsed is None:
563
+ print(
564
+ f"invalid run/checkpoint reference {args.run_id!r} "
565
+ "(expected <run_id> or <run_id>/step-N)",
566
+ file=sys.stderr,
567
+ )
568
+ return 1
569
+ base_run_id, _step = parsed
570
+ client = client_from_config()
571
+ dep = client.deploy(
567
572
  args.run_id,
568
573
  dry_run=args.dry_run,
569
- step=getattr(args, "step", None),
574
+ verify=not getattr(args, "no_verify", False),
570
575
  )
571
576
  if render.styled():
572
577
  print(render.deployed(dep))
@@ -574,12 +579,43 @@ def cmd_deploy(args) -> int:
574
579
  print(json.dumps(dep, indent=2))
575
580
  # a dry run creates no deployment, so the billing / undeploy hint would be misleading.
576
581
  if dep.get("state") != "dry_run":
582
+ endpoint = str(dep.get("endpoint_name") or "").rstrip("/")
583
+ openai_base = dep.get("url") or (f"{endpoint}/v1" if endpoint else "")
577
584
  note = (
578
- f"serving is billed per token only; use `flash undeploy {args.run_id}` "
585
+ f"serving is billed per token only; use `flash undeploy {base_run_id}` "
579
586
  "to deregister the adapter."
580
587
  )
581
588
  print(render.arrow(note) if render.styled() else f"note: {note}", file=sys.stderr)
582
- return 0
589
+ if openai_base:
590
+ url_note = (
591
+ f"OpenAI-compatible base URL: {openai_base} — point clients at this /v1 base, "
592
+ "not the bare endpoint (which 404s on /chat/completions)."
593
+ )
594
+ print(render.arrow(url_note) if render.styled() else f"note: {url_note}", file=sys.stderr)
595
+ if dep.get("state") != "dry_run":
596
+ state = dep.get("state", "deploying")
597
+ if state == "failed":
598
+ detail = str(dep.get("error") or dep.get("detail") or "unknown error")
599
+ status_note = (
600
+ f"deployment failed: {detail}; run `flash deployments` for details and "
601
+ f"retry `flash deploy {args.run_id}` after fixing the error."
602
+ )
603
+ else:
604
+ status_note = (
605
+ f"deployment state is {state!r}; run `flash deployments` to check progress "
606
+ "and use `flash chat` once it is ready."
607
+ )
608
+ print(
609
+ render.arrow(status_note) if render.styled() else f"note: {status_note}",
610
+ file=sys.stderr,
611
+ )
612
+ if getattr(args, "no_verify", False):
613
+ skip_note = "server-side smoke verification was skipped for this deployment."
614
+ print(
615
+ render.arrow(skip_note) if render.styled() else f"note: {skip_note}",
616
+ file=sys.stderr,
617
+ )
618
+ return 1 if dep.get("state") == "failed" else 0
583
619
 
584
620
 
585
621
  def cmd_export(args) -> int:
@@ -592,9 +628,8 @@ def cmd_export(args) -> int:
592
628
  "(export it in your shell or put it in a local .env / .env.local)"
593
629
  )
594
630
  client = client_from_config()
595
- where = f" (step {args.step})" if args.step is not None else ""
596
631
  progress = (
597
- f"exporting adapter {args.adapter_id}{where} to {args.repository} — "
632
+ f"exporting adapter {args.adapter_id} to {args.repository} — "
598
633
  "downloading then re-uploading; this can take a minute..."
599
634
  )
600
635
  print(render.note(progress) if render.styled() else progress, file=sys.stderr)
@@ -602,7 +637,6 @@ def cmd_export(args) -> int:
602
637
  args.adapter_id,
603
638
  repository=args.repository,
604
639
  hf_token=hf_token,
605
- step=args.step,
606
640
  private=not args.public,
607
641
  )
608
642
  if render.styled():
@@ -639,23 +673,41 @@ def cmd_deployments(args) -> int:
639
673
  if render.styled():
640
674
  print(render.deployments_table(rows))
641
675
  return 0
642
- print(f"{'RUN_ID':<32} {'GPU':<9} ENDPOINT")
676
+ print(f"{'RUN_ID':<32} {'STATE':<10} {'GPU':<9} {'ENDPOINT':<32} DETAIL")
643
677
  for r in rows:
644
678
  d = r.get("deployment") or {}
645
- print(f"{r['run_id']:<32} {d.get('gpu', '?'):<9} {d.get('endpoint_name', '')}")
679
+ detail = str(d.get("error") or d.get("detail") or "")
680
+ print(
681
+ f"{r['run_id']:<32} {d.get('state', '?'):<10} "
682
+ f"{d.get('gpu', '?'):<9} {d.get('endpoint_name', ''):<32} {detail}"
683
+ )
646
684
  return 0
647
685
 
648
686
 
649
687
  def cmd_chat(args) -> int:
688
+ from flash.schema import parse_checkpoint_ref
689
+
690
+ parsed = parse_checkpoint_ref(args.run_id)
691
+ if parsed is None:
692
+ print(
693
+ f"invalid run/checkpoint reference {args.run_id!r} "
694
+ "(expected <run_id> or <run_id>/step-N)",
695
+ file=sys.stderr,
696
+ )
697
+ return 1
698
+ base_run_id, _step = parsed
650
699
  client = client_from_config()
651
700
  messages = [{"role": "user", "content": args.message}]
701
+ system = getattr(args, "system", None)
702
+ if system:
703
+ messages.insert(0, {"role": "system", "content": system})
652
704
  if render.styled():
653
705
  print(render.chat_label())
654
706
  stream = getattr(client, "chat_stream", None)
655
707
  if stream is not None:
656
708
  wrote = False
657
709
  for chunk in stream(
658
- args.run_id,
710
+ base_run_id,
659
711
  messages=messages,
660
712
  temperature=args.temperature,
661
713
  max_tokens=args.max_tokens,
@@ -667,7 +719,7 @@ def cmd_chat(args) -> int:
667
719
  return 0
668
720
 
669
721
  resp = client.chat(
670
- args.run_id,
722
+ base_run_id,
671
723
  messages=messages,
672
724
  temperature=args.temperature,
673
725
  max_tokens=args.max_tokens,
@@ -188,25 +188,23 @@ _ENV_PUSH_SIDECAR_SUFFIXES = frozenset(
188
188
 
189
189
 
190
190
  def _normalize_env_name(raw: str) -> str | None:
191
- import re
191
+ """Normalize only the NAME segment; a namespace prefix is passed through verbatim.
192
192
 
193
- def normalize_segment(value: str) -> str | None:
194
- segment = re.sub(r"[^a-z0-9._-]+", "-", value.lower()).strip("-")
195
- if segment in {"", ".", ".."} or not re.search(r"[a-z0-9]", segment):
196
- return None
197
- return segment
193
+ The server is the sole authority on namespace grammar and ownership — rewriting the
194
+ namespace client-side would silently target a different (possibly forbidden) slug.
195
+ """
196
+ from flash.schema import normalize_env_name_segment
198
197
 
199
198
  text = str(raw or "").strip()
200
199
  if "/" not in text:
201
- return normalize_segment(text)
200
+ return normalize_env_name_segment(text)
202
201
  parts = [part.strip() for part in text.split("/")]
203
202
  if len(parts) != 2 or not all(parts):
204
203
  return None
205
- namespace = normalize_segment(parts[0])
206
- name = normalize_segment(parts[1])
207
- if not namespace or not name:
204
+ name = normalize_env_name_segment(parts[1])
205
+ if name is None:
208
206
  return None
209
- return f"{namespace}/{name}"
207
+ return f"{parts[0]}/{name}"
210
208
 
211
209
 
212
210
  def _with_syspath_bootstrap(env_source: str) -> str:
@@ -439,28 +439,37 @@ def deployments_table(rows: list[dict]) -> str:
439
439
  body = []
440
440
  for r in rows:
441
441
  d = r.get("deployment") or {}
442
+ state = str(d.get("state") or "?")
443
+ color = _GREEN if state in {"ready", "deployed"} else _RED if state == "failed" else _AMBER
444
+ detail = str(d.get("error") or d.get("detail") or "")
445
+ if len(detail) > 64:
446
+ detail = detail[:61] + "..."
442
447
  body.append(
443
448
  [
444
449
  (r["run_id"], _ACCENT2),
450
+ (state, color),
445
451
  (d.get("gpu", "?"), _GRAY),
446
452
  (d.get("endpoint_name", ""), _GREEN),
453
+ (detail, _GRAY),
447
454
  ]
448
455
  )
449
- table = _table(["RUN ID", "GPU", "ENDPOINT"], body)
456
+ table = _table(["RUN ID", "STATE", "GPU", "ENDPOINT", "DETAIL"], body)
450
457
  return _safe(f"{header('deployments', f'{len(rows)} active')}\n{table}")
451
458
 
452
459
 
453
460
  def checkpoints_table(run_id: str, rows: list[dict]) -> str:
454
- """Deployable per-step RL checkpoints: the step number + the stable repo path it lives at."""
461
+ """Deployable per-step RL checkpoints: step number + the canonical `<run_id>/step-N` ref."""
462
+ from flash.schema import format_checkpoint_ref
463
+
455
464
  body = [
456
465
  [
457
466
  (str(c.get("step", "")), _TEAL),
458
- (f"{c.get('repo_id', '')}:{c.get('subfolder', '')}", _ACCENT2),
467
+ (format_checkpoint_ref(run_id, c.get("step", 0)), _ACCENT2),
459
468
  ]
460
469
  for c in sorted(rows, key=lambda c: c.get("step", 0))
461
470
  ]
462
471
  table = _table(["STEP", "CHECKPOINT"], body, aligns=["r", "l"])
463
- foot = arrow(f"deploy one with: flash deploy {run_id} --step <STEP>")
472
+ foot = arrow(f"deploy one with: flash deploy {run_id}/step-<STEP>")
464
473
  return _safe(f"{header('checkpoints', f'{len(rows)} deployable')}\n{table}\n\n{foot}")
465
474
 
466
475
 
@@ -541,11 +550,14 @@ def cancelled(payload: dict) -> str:
541
550
 
542
551
  def deployed(dep: dict) -> str:
543
552
  """`flash deploy`: the endpoint, gpu, and serving url as an aligned card (not a JSON dump)."""
553
+ endpoint = str(dep.get("endpoint_name") or "")
554
+ # OpenAI clients need the /v1 base; older servers omit `url`, so derive it from the endpoint.
555
+ url = dep.get("url") or (f"{endpoint.rstrip('/')}/v1" if endpoint else None)
544
556
  pairs = [
545
557
  ("run", _paint(dep.get("run_id", ""), _ACCENT2)),
546
- ("endpoint", _paint(dep["endpoint_name"], _GREEN) if dep.get("endpoint_name") else None),
558
+ ("endpoint", _paint(endpoint, _GREEN) if endpoint else None),
547
559
  ("gpu", dep.get("gpu")),
548
- ("url", _paint(dep["url"], _ACCENT2) if dep.get("url") else None),
560
+ ("url", _paint(url, _ACCENT2) if url else None),
549
561
  ]
550
562
  state = dep.get("state", "deployed")
551
563
  if state == "dry_run":
@@ -571,6 +583,10 @@ def undeployed(result: dict) -> str:
571
583
  line = ok(f"torn down {rid}")
572
584
  if deleted:
573
585
  line += "\n" + _dim(f" deregistered {', '.join(deleted)}")
586
+ else:
587
+ line += "\n" + _dim(
588
+ " serving had no registered adapter to deregister (already gone or never registered)"
589
+ )
574
590
  return _safe(line)
575
591
 
576
592
 
@@ -138,7 +138,8 @@ flash cancel <run-id> # stop a run
138
138
 
139
139
  ```bash
140
140
  flash checkpoints <run-id> # deployable per-step RL checkpoints
141
- flash deploy <run-id> # serve the trained adapter (--step N for an intermediate checkpoint)
141
+ flash deploy <run-id> # serve the trained adapter
142
+ flash deploy <run-id>/step-N # serve an intermediate checkpoint
142
143
  flash chat <run-id> -m "hello" # chat with the deployed adapter
143
144
  flash deployments # active serving endpoints
144
145
  flash undeploy <run-id> # tear the endpoint down
@@ -208,7 +209,7 @@ spending another GPU run:
208
209
  | Output is truncated | Correct-looking answers cut off mid-response or JSON is incomplete | Increase `max_tokens` for GRPO rollouts or `max_length` for SFT only after seeing truncation. Oversizing them by default just burns memory/cost. |
209
210
  | Infrastructure, CUDA, OOM, vLLM, or kernel failure | Run errors before useful metrics, often during setup/model load | Treat this as infrastructure pressure, not proof the model is too large. Read `flash log <run-id>`, reduce footprint (`max_length`, `max_tokens`, `group_size`) if needed, and let Flash retry/allocate another fitting GPU class. |
210
211
  | Run looks stuck after disconnecting | Terminal stopped streaming but the job may still be alive | Ctrl-C detaches. Use `flash log <run-id> --follow` to reattach, `flash log <run-id>` for the console/error output, or `flash cancel <run-id>` if you intentionally want to stop it. |
211
- | 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. |
212
+ | 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. |
212
213
  | 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`. |
213
214
  | 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. |
214
215
  | 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. |
@@ -350,9 +351,9 @@ Pick SFT when you already have good answers and want the model to imitate them.
350
351
  algorithm = "grpo"
351
352
 
352
353
  [train]
353
- # paste the full adapter_ref `flash status <sft-run-id>` prints, verbatim
354
- # (shape: <owner>/<repo>:sft/<run-id> the owner/repo prefix is required)
355
- init_from_adapter = "your-org/your-repo:sft/<sft-run-id>"
354
+ # the SFT run id (as printed by `flash status`); add /step-N to warm-start from a
355
+ # specific checkpoint listed by `flash checkpoints <run-id>`
356
+ init_from_adapter = "<sft-run-id>"
356
357
  lora_rank = 16 # for VL warm-starts, SFT rank + GRPO rank must fit the effective serving cap
357
358
  lora_alpha = 32
358
359
  ```
@@ -479,12 +480,12 @@ flash runs # list your runs and their state/cost
479
480
  flash cancel <run-id> # stop a live run
480
481
  flash checkpoints <run-id> # list deployable RL checkpoints
481
482
  flash deploy <run-id> # serve the trained adapter
482
- flash deploy <run-id> --step N # serve a specific RL checkpoint
483
+ flash deploy <run-id>/step-N # serve a specific RL checkpoint
483
484
  flash chat <run-id> -m "probe" # stream a reply from the deployed adapter
484
485
  flash deployments # list active serving deployments
485
486
  flash undeploy <run-id> # tear down an active deployment
486
487
  flash export --adapter-id <run-id> --repository <you>/<repo> # export final adapter
487
- flash export --adapter-id <run-id> --repository <you>/<repo> --step N # export a checkpoint
488
+ flash export --adapter-id <run-id>/step-N --repository <you>/<repo> # export a checkpoint
488
489
  ```
489
490
 
490
491
  See the full reference at https://freesolo.co/docs.