freesolo-flash-dev 0.2.41__tar.gz → 0.2.42__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 (299) hide show
  1. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/PKG-INFO +1 -1
  2. freesolo_flash_dev-0.2.42/docs/cli-style/env-setup-survey-dark.png +0 -0
  3. freesolo_flash_dev-0.2.42/docs/cli-style/env-setup-survey-light.png +0 -0
  4. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cli/__init__.py +25 -1
  5. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cli/commands.py +106 -15
  6. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cli/render.py +32 -0
  7. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_worker.py +5 -4
  8. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/pyproject.toml +2 -2
  9. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cli_commands.py +103 -0
  10. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_flash_worker.py +1 -1
  11. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/uv.lock +1 -1
  12. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.dockerignore +0 -0
  13. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.env.example +0 -0
  14. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/auto-rebake.yml +0 -0
  15. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/bake-kernel-cache.yml +0 -0
  16. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/ci.yml +0 -0
  17. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/main-source-guard.yml +0 -0
  18. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/notify-tests-repo.yml +0 -0
  19. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/publish-dev.yml +0 -0
  20. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/publish-image.yml +0 -0
  21. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/publish.yml +0 -0
  22. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/version-parity.yml +0 -0
  23. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.github/workflows/worker-image.yml +0 -0
  24. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/.gitignore +0 -0
  25. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/Dockerfile +0 -0
  26. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/Dockerfile.worker +0 -0
  27. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/LICENSE +0 -0
  28. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/README.md +0 -0
  29. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/build/kernel_cache/.gitignore +0 -0
  30. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/build/kernel_cache/.keep +0 -0
  31. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docker/Dockerfile.kernelcache +0 -0
  32. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docker/Dockerfile.kernelcache.relayer +0 -0
  33. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docker/bake_kernel_cache.py +0 -0
  34. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docker/bake_pod_entry.py +0 -0
  35. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docker/kernel_fingerprint.py +0 -0
  36. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docker/make_rp_handler.py +0 -0
  37. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/cli-style/README.md +0 -0
  38. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/cli-style/generate.py +0 -0
  39. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/cli-style/index.html +0 -0
  40. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/cli-style/preview.png +0 -0
  41. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/cli-style/themed-errors.png +0 -0
  42. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/cli-style/train-config-error-after.png +0 -0
  43. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/cli-style/train-config-error-before.png +0 -0
  44. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/docs/kernel-cache.md +0 -0
  45. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/__init__.py +0 -0
  46. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/_channel.py +0 -0
  47. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/_fileio.py +0 -0
  48. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/_logging.py +0 -0
  49. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/_update_check.py +0 -0
  50. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/adapter_artifacts.py +0 -0
  51. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/catalog.py +0 -0
  52. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cli/__main__.py +0 -0
  53. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cli/_tty.py +0 -0
  54. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cli/envpush.py +0 -0
  55. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cli/training_doc.py +0 -0
  56. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/client/__init__.py +0 -0
  57. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/client/config.py +0 -0
  58. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/client/http.py +0 -0
  59. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/client/runtime_secrets.py +0 -0
  60. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/client/specs.py +0 -0
  61. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cost/__init__.py +0 -0
  62. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cost/analytical.py +0 -0
  63. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cost/facts.py +0 -0
  64. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cost/spec.py +0 -0
  65. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/cost/types.py +0 -0
  66. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/__init__.py +0 -0
  67. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/accounting.py +0 -0
  68. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/chalk_kernels.py +0 -0
  69. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/multiturn_rollout.py +0 -0
  70. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/recipe.py +0 -0
  71. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/vram.py +0 -0
  72. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/__init__.py +0 -0
  73. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/__main__.py +0 -0
  74. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/_pkg.py +0 -0
  75. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/adapter.py +0 -0
  76. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/decoding.py +0 -0
  77. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/finalize.py +0 -0
  78. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/gpu_setup.py +0 -0
  79. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/grpo.py +0 -0
  80. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/heartbeat.py +0 -0
  81. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/hf.py +0 -0
  82. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/kernel_warmup.py +0 -0
  83. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/lora.py +0 -0
  84. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/packing.py +0 -0
  85. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/perf/__init__.py +0 -0
  86. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/perf/attn.py +0 -0
  87. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/perf/diagnostics.py +0 -0
  88. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/perf/lifecycle.py +0 -0
  89. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/perf/liger.py +0 -0
  90. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/perf/loraplus.py +0 -0
  91. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/perf/memory.py +0 -0
  92. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/rl.py +0 -0
  93. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/sft.py +0 -0
  94. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/engine/worker/wandb_log.py +0 -0
  95. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/envs/__init__.py +0 -0
  96. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/envs/adapter.py +0 -0
  97. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/envs/archive_policy.py +0 -0
  98. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/envs/base.py +0 -0
  99. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/envs/loader.py +0 -0
  100. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/envs/pull.py +0 -0
  101. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/envs/registry.py +0 -0
  102. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/lora_rank.py +0 -0
  103. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/__init__.py +0 -0
  104. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_auth.py +0 -0
  105. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_hf_artifacts.py +0 -0
  106. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_hf_retry.py +0 -0
  107. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_http.py +0 -0
  108. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_instance.py +0 -0
  109. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_instance_bootstrap.py +0 -0
  110. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_instance_poll.py +0 -0
  111. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_instance_provider.py +0 -0
  112. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/_poll.py +0 -0
  113. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/allocator.py +0 -0
  114. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/base.py +0 -0
  115. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/__init__.py +0 -0
  116. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/api.py +0 -0
  117. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/auth.py +0 -0
  118. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/gpus.py +0 -0
  119. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
  120. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/jobs/builders.py +0 -0
  121. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/preflight.py +0 -0
  122. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/lambdalabs/pricing.py +0 -0
  123. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/preflight.py +0 -0
  124. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/realized.py +0 -0
  125. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/__init__.py +0 -0
  126. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/api.py +0 -0
  127. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/auth.py +0 -0
  128. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/cost.py +0 -0
  129. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/gpus.py +0 -0
  130. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/jobs.py +0 -0
  131. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/keys.py +0 -0
  132. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/preflight.py +0 -0
  133. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/preload.py +0 -0
  134. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/pricing.py +0 -0
  135. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/slots.py +0 -0
  136. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/train/__init__.py +0 -0
  137. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/train/deps.py +0 -0
  138. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/runpod/train/endpoints.py +0 -0
  139. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/vast/__init__.py +0 -0
  140. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/vast/api.py +0 -0
  141. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/vast/auth.py +0 -0
  142. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/vast/jobs/__init__.py +0 -0
  143. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/vast/jobs/builders.py +0 -0
  144. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/vast/preflight.py +0 -0
  145. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/providers/vast/pricing.py +0 -0
  146. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/py.typed +0 -0
  147. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/runner/__init__.py +0 -0
  148. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/runner/checkpoints.py +0 -0
  149. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/runner/deploy.py +0 -0
  150. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/runner/lifecycle.py +0 -0
  151. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/schema/__init__.py +0 -0
  152. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/schema/fields.py +0 -0
  153. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/serve/__init__.py +0 -0
  154. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/serve/deploy.py +0 -0
  155. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/serve/export.py +0 -0
  156. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/serve/pricing.py +0 -0
  157. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/__init__.py +0 -0
  158. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/__main__.py +0 -0
  159. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/_deps.py +0 -0
  160. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/_internal_client.py +0 -0
  161. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/_locks.py +0 -0
  162. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/_runtime.py +0 -0
  163. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/app.py +0 -0
  164. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/auth.py +0 -0
  165. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/billing.py +0 -0
  166. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/billing_retry.py +0 -0
  167. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/checkpoints.py +0 -0
  168. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/db.py +0 -0
  169. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/environment_registry.py +0 -0
  170. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/envs.py +0 -0
  171. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/reconcile.py +0 -0
  172. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/routes/__init__.py +0 -0
  173. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/routes/envs.py +0 -0
  174. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/routes/meta.py +0 -0
  175. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/routes/runs.py +0 -0
  176. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/routes/serving.py +0 -0
  177. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/server/run_registry.py +0 -0
  178. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/flash/spec.py +0 -0
  179. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/infisical-entrypoint.sh +0 -0
  180. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/scripts/build_dev_dist.py +0 -0
  181. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/__init__.py +0 -0
  182. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/_helpers/__init__.py +0 -0
  183. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/_helpers/runner.py +0 -0
  184. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/_helpers/specs.py +0 -0
  185. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/_helpers/vast.py +0 -0
  186. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/conftest.py +0 -0
  187. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/fixtures/math_eval.jsonl +0 -0
  188. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/fixtures/math_train.jsonl +0 -0
  189. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/live/__init__.py +0 -0
  190. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/live/conftest.py +0 -0
  191. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/live/test_lambda_live.py +0 -0
  192. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/live/test_runpod_live.py +0 -0
  193. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/live/test_vast_live.py +0 -0
  194. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_agent_flash_cli_contract.py +0 -0
  195. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_algorithms.py +0 -0
  196. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_allocator.py +0 -0
  197. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_b200_rollout_opt.py +0 -0
  198. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_backend_jobspec_contract.py +0 -0
  199. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_billing_retry.py +0 -0
  200. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cancel_remote.py +0 -0
  201. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_catalog_consistency.py +0 -0
  202. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_chalk_kernels.py +0 -0
  203. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_charge_pricing.py +0 -0
  204. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_checkpoints.py +0 -0
  205. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cli_errors.py +0 -0
  206. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cli_estimate.py +0 -0
  207. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cli_help.py +0 -0
  208. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cli_managed.py +0 -0
  209. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cli_render_theme.py +0 -0
  210. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_client.py +0 -0
  211. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_client_server_integration.py +0 -0
  212. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_config_overrides.py +0 -0
  213. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cost_analytical.py +0 -0
  214. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cost_equation.py +0 -0
  215. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cost_estimate.py +0 -0
  216. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cost_hardware.py +0 -0
  217. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cost_models.py +0 -0
  218. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_cost_rewards.py +0 -0
  219. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_dev_channel.py +0 -0
  220. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_disk_gb.py +0 -0
  221. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_endpoint_name.py +0 -0
  222. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_cache_evict.py +0 -0
  223. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_delete.py +0 -0
  224. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_download.py +0 -0
  225. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_download_api.py +0 -0
  226. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_no_install.py +0 -0
  227. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_publish.py +0 -0
  228. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_pull.py +0 -0
  229. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_pull_managed_control_plane.py +0 -0
  230. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_push.py +0 -0
  231. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_env_rate_limit_resolve.py +0 -0
  232. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_envs_coverage.py +0 -0
  233. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_export.py +0 -0
  234. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_flash_mvp.py +0 -0
  235. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_flashinfer_cache_dirs.py +0 -0
  236. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_github_urlopen_retry.py +0 -0
  237. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_gpus.py +0 -0
  238. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_grpo_mask_aware.py +0 -0
  239. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_grpo_params.py +0 -0
  240. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_grpo_sleep_gate.py +0 -0
  241. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_health_liveness.py +0 -0
  242. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_idle_endpoint_reaper.py +0 -0
  243. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_internal_client.py +0 -0
  244. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_jobs.py +0 -0
  245. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_kernel_cache.py +0 -0
  246. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_kernel_fingerprint.py +0 -0
  247. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_kv_util.py +0 -0
  248. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_lambda_runner.py +0 -0
  249. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_logging.py +0 -0
  250. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_login_perms.py +0 -0
  251. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_lora_rank_preflight.py +0 -0
  252. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_managed_hf_repo.py +0 -0
  253. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_metrics_schema_agent_contract.py +0 -0
  254. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_mig_guard.py +0 -0
  255. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_multiturn_rollout.py +0 -0
  256. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_oom_escalate_gpu.py +0 -0
  257. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_open_model_policy.py +0 -0
  258. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_orchestrator_flash.py +0 -0
  259. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_packing.py +0 -0
  260. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_poll_helpers.py +0 -0
  261. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_preflight.py +0 -0
  262. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_provider_routing.py +0 -0
  263. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_provider_teardown_robustness.py +0 -0
  264. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_providers_symmetry.py +0 -0
  265. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_realized_cost.py +0 -0
  266. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_resolve_params_b.py +0 -0
  267. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_resume_on_retry.py +0 -0
  268. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_runmgmt.py +0 -0
  269. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_runpod_api_delete.py +0 -0
  270. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_runpod_key_fingerprint.py +0 -0
  271. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_runpod_key_waterfall.py +0 -0
  272. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_runpod_slots.py +0 -0
  273. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_serve.py +0 -0
  274. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_server_api.py +0 -0
  275. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_server_billing.py +0 -0
  276. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_server_db.py +0 -0
  277. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_serving_contract.py +0 -0
  278. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_sft_gc_off.py +0 -0
  279. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_spec_and_validation.py +0 -0
  280. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_thinking_config.py +0 -0
  281. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_train_context_preflight.py +0 -0
  282. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_update_check.py +0 -0
  283. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_vast_api.py +0 -0
  284. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_vast_offers.py +0 -0
  285. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_vast_runner.py +0 -0
  286. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_verifiers.py +0 -0
  287. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_version.py +0 -0
  288. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  289. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_vl_warmstart_recombine.py +0 -0
  290. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_vl_weight_sync.py +0 -0
  291. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_wandb_naming.py +0 -0
  292. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_warmstart_cross_repo.py +0 -0
  293. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_weight_cache.py +0 -0
  294. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_worker_dryrun.py +0 -0
  295. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_worker_hardexit.py +0 -0
  296. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_worker_image.py +0 -0
  297. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_worker_init_heartbeat.py +0 -0
  298. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_worker_stack.py +0 -0
  299. {freesolo_flash_dev-0.2.41 → freesolo_flash_dev-0.2.42}/tests/test_worker_thinking.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freesolo-flash-dev
3
- Version: 0.2.41
3
+ Version: 0.2.42
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
@@ -249,7 +249,31 @@ def _build_parser() -> argparse.ArgumentParser:
249
249
  const="multi",
250
250
  help="scaffold a multi-turn environment (bounded episode with step_episode / score_episode).",
251
251
  )
252
- setup.set_defaults(func=cmd_env_setup, turn_mode="single")
252
+ setup_reason = setup.add_mutually_exclusive_group()
253
+ setup_reason.add_argument(
254
+ "--reasoning",
255
+ dest="reasoning",
256
+ action="store_const",
257
+ const=True,
258
+ help="scaffold configs with reasoning enabled (thinking = true, with a raised token budget).",
259
+ )
260
+ setup_reason.add_argument(
261
+ "--no-reasoning",
262
+ dest="reasoning",
263
+ action="store_const",
264
+ const=False,
265
+ help="scaffold configs without reasoning. This is the default.",
266
+ )
267
+ setup.add_argument(
268
+ "-y",
269
+ "--yes",
270
+ dest="yes",
271
+ action="store_true",
272
+ help="accept defaults without prompting (single-turn, no reasoning).",
273
+ )
274
+ # turn_mode / reasoning default to None (unset) so the scaffold can tell an explicit flag
275
+ # apart from "not chosen yet" and, on an interactive terminal, ask instead of assuming.
276
+ setup.set_defaults(func=cmd_env_setup, turn_mode=None, reasoning=None, yes=False)
253
277
 
254
278
  env_list = env_sub.add_parser("list", help="list local environment sources")
255
279
  env_list.set_defaults(func=cmd_env_list)
@@ -330,14 +330,40 @@ _STARTER_DATASET_MULTITURN_JSONL = """\
330
330
  """
331
331
 
332
332
 
333
+ _TURN_OPTIONS = [
334
+ ("single", "single-turn", "one prompt -> one response"),
335
+ ("multi", "multi-turn", "bounded episode: step_episode / score_episode"),
336
+ ]
337
+ _REASONING_OPTIONS = [
338
+ ("off", "no reasoning", "the model answers directly"),
339
+ ("on", "reasoning", "thinking = true; spends more tokens per answer"),
340
+ ]
341
+
342
+
343
+ def _setup_interactive(args) -> bool:
344
+ """Whether to ask the setup questions interactively.
345
+
346
+ Prompt only on a real terminal a human can answer from. Fall back to defaults (no prompt) when
347
+ --yes is passed, under CI, or when stdin is closed/redirected, so automation never blocks on an
348
+ unanswered prompt. A pseudo-TTY in CI can report isatty()=True, so CI is checked explicitly; a
349
+ closed fd 0 can make sys.stdin None, so that is guarded before .isatty()."""
350
+ if getattr(args, "yes", False):
351
+ return False
352
+ if os.environ.get("CI", "").strip().lower() not in ("", "0", "false", "no"):
353
+ return False
354
+ stdin = sys.stdin
355
+ if stdin is None or not stdin.isatty():
356
+ return False
357
+ return render.styled()
358
+
359
+
333
360
  def cmd_env_setup(args) -> int:
334
- requested_multi = getattr(args, "turn_mode", "single") == "multi"
335
361
  starter_env = Path("environment.py")
336
362
  dataset = Path("dataset/train.jsonl")
337
363
  # An existing environment.py is the authoritative signal for which turn mode this
338
364
  # scaffold already uses (the dataset is plain JSONL with no reliable mode marker).
339
365
  # Anchor to it so a re-run never leaves a single-turn env beside a multi-turn
340
- # dataset (or vice versa); the flag only decides the mode when starting fresh.
366
+ # dataset (or vice versa); the flag/answer only decides the mode when starting fresh.
341
367
  existing_multi: bool | None = None
342
368
  anchor = "environment.py"
343
369
  if starter_env.exists():
@@ -347,15 +373,59 @@ def cmd_env_setup(args) -> int:
347
373
  # distinctive prompt; use it so we don't drop a single-turn env beside it.
348
374
  existing_multi = "secret whole number" in dataset.read_text(encoding="utf-8")
349
375
  anchor = "dataset/train.jsonl"
350
- if existing_multi is not None and existing_multi != requested_multi:
351
- have = "multi-turn" if existing_multi else "single-turn"
352
- want = "multi-turn" if requested_multi else "single-turn"
353
- msg = (
354
- f"existing {anchor} is {have}; keeping it and ignoring --{want}. "
355
- f"Delete environment.py and dataset/train.jsonl first to re-scaffold as {want}."
376
+
377
+ # Resolve the turn mode. An existing scaffold wins (warn if a flag disagrees); otherwise an
378
+ # explicit --single-turn/--multi-turn flag wins; otherwise ask on a terminal, else single-turn.
379
+ flag_mode = getattr(args, "turn_mode", None)
380
+ if existing_multi is not None:
381
+ if flag_mode is not None and (flag_mode == "multi") != existing_multi:
382
+ have = "multi-turn" if existing_multi else "single-turn"
383
+ want = "multi-turn" if flag_mode == "multi" else "single-turn"
384
+ msg = (
385
+ f"existing {anchor} is {have}; keeping it and ignoring --{want}. "
386
+ f"Delete environment.py and dataset/train.jsonl first to re-scaffold as {want}."
387
+ )
388
+ print(render.warn(msg) if render.styled() else f"warning: {msg}", file=sys.stderr)
389
+ multi_turn = existing_multi
390
+ elif flag_mode is not None:
391
+ multi_turn = flag_mode == "multi"
392
+ elif _setup_interactive(args):
393
+ multi_turn = (
394
+ render.select("How does the model interact with your task?", _TURN_OPTIONS) == "multi"
356
395
  )
357
- print(render.warn(msg) if render.styled() else f"warning: {msg}", file=sys.stderr)
358
- multi_turn = requested_multi if existing_multi is None else existing_multi
396
+ else:
397
+ multi_turn = False
398
+
399
+ # Resolve reasoning. Like the turn mode, an existing config is authoritative: configs are only
400
+ # written when absent, so applying a reasoning flag to an already-scaffolded project would
401
+ # silently no-op (or write one config with reasoning and leave the other without). Anchor to the
402
+ # existing config's `thinking` state and warn if a flag disagrees; otherwise the flag wins;
403
+ # otherwise ask on a terminal; else off.
404
+ rl = Path("configs/rl.toml")
405
+ sft = Path("configs/sft.toml")
406
+ existing_reasoning: bool | None = None
407
+ for cfg in (rl, sft):
408
+ if cfg.exists():
409
+ existing_reasoning = "thinking = true" in cfg.read_text(encoding="utf-8")
410
+ break
411
+ flag_reason = getattr(args, "reasoning", None)
412
+ if existing_reasoning is not None:
413
+ if flag_reason is not None and flag_reason != existing_reasoning:
414
+ have = "reasoning" if existing_reasoning else "no reasoning"
415
+ want = "reasoning" if flag_reason else "no-reasoning"
416
+ msg = (
417
+ f"existing configs are {have}; keeping them and ignoring --{want}. "
418
+ f"Delete configs/rl.toml and configs/sft.toml first to re-scaffold with --{want}."
419
+ )
420
+ print(render.warn(msg) if render.styled() else f"warning: {msg}", file=sys.stderr)
421
+ reasoning = existing_reasoning
422
+ elif flag_reason is not None:
423
+ reasoning = flag_reason
424
+ elif _setup_interactive(args):
425
+ reasoning = render.select("Train with reasoning (thinking)?", _REASONING_OPTIONS) == "on"
426
+ else:
427
+ reasoning = False
428
+
359
429
  env_py = _STARTER_ENV_MULTITURN_PY if multi_turn else _STARTER_ENV_PY
360
430
  dataset_jsonl = _STARTER_DATASET_MULTITURN_JSONL if multi_turn else _STARTER_DATASET_JSONL
361
431
  Path("configs").mkdir(exist_ok=True)
@@ -373,28 +443,47 @@ def cmd_env_setup(args) -> int:
373
443
  'id = ""\n\n'
374
444
  '# secrets = ["SERPAPI_API_KEY"]\n\n'
375
445
  )
376
- rl = Path("configs/rl.toml")
446
+ # `thinking = true` opts the run into reasoning mode. Reasoning shares the generation budget with
447
+ # the answer, so GRPO also gets a raised max_tokens. These strings are empty when reasoning is
448
+ # off, keeping the default scaffold byte-for-byte identical.
449
+ thinking_line = "thinking = true\n" if reasoning else ""
450
+ rl_reasoning_train = (
451
+ "max_tokens = 2048 # reasoning shares this budget with the answer; raised so it isn't truncated\n"
452
+ if reasoning
453
+ else ""
454
+ )
455
+ sft_reasoning_note = (
456
+ "# reasoning is on (thinking = true): each gold `output` must contain a <think>...</think>\n"
457
+ "# block; validate locally with freesolo.datasets.warn_missing_think_tags before a real run.\n"
458
+ if reasoning
459
+ else ""
460
+ )
377
461
  if not rl.exists():
378
462
  rl.write_text(
379
463
  'model = "Qwen/Qwen3.5-4B"\n'
380
- 'algorithm = "grpo"\n\n'
464
+ 'algorithm = "grpo"\n'
465
+ f"{thinking_line}"
466
+ "\n"
381
467
  f"{env_comment}"
382
468
  "[train]\n"
383
469
  "steps = 150\n"
470
+ f"{rl_reasoning_train}"
384
471
  "lora_rank = 32\n"
385
472
  "# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
386
473
  "# the cheapest fitting managed class, and artifacts live in a private environment-scoped repo.\n"
387
474
  )
388
- sft = Path("configs/sft.toml")
389
475
  if not sft.exists():
390
476
  sft.write_text(
391
477
  'model = "Qwen/Qwen3.5-4B"\n'
392
- 'algorithm = "sft"\n\n'
478
+ 'algorithm = "sft"\n'
479
+ f"{thinking_line}"
480
+ "\n"
393
481
  f"{env_comment}"
394
482
  "[train]\n"
395
483
  "epochs = 1\n"
396
484
  "max_examples = 2 # rows to train on; the starter dataset has 2 (raise as your dataset grows)\n"
397
485
  "lora_rank = 32\n"
486
+ f"{sft_reasoning_note}"
398
487
  "# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
399
488
  "# the cheapest fitting managed class, and artifacts live in a private environment-scoped repo.\n"
400
489
  )
@@ -768,7 +857,9 @@ def cmd_deploy(args) -> int:
768
857
  f"OpenAI-compatible base URL: {openai_base} — point clients at this /v1 base, "
769
858
  "not the bare endpoint (which 404s on /chat/completions)."
770
859
  )
771
- print(render.arrow(url_note) if render.styled() else f"note: {url_note}", file=sys.stderr)
860
+ print(
861
+ render.arrow(url_note) if render.styled() else f"note: {url_note}", file=sys.stderr
862
+ )
772
863
  if dep.get("state") != "dry_run":
773
864
  state = dep.get("state", "deploying")
774
865
  if state == "failed":
@@ -273,6 +273,38 @@ def arrow(msg: str) -> str:
273
273
  return _safe(f"{_paint(_glyph('→', '->'), _ACCENT2)} {_dim(msg)}")
274
274
 
275
275
 
276
+ def select(title: str, options: list[tuple[str, str, str]], default: int = 0) -> str:
277
+ """Themed single-choice prompt; returns the chosen option's value.
278
+
279
+ ``options`` is a list of ``(value, label, hint)``. The default option is marked and taken on
280
+ an empty answer (enter). Reads via ``input()`` so it is easy to drive in tests; the caller
281
+ decides *when* to prompt (interactive stdin), so this always prompts when called. On EOF the
282
+ default is returned so a closed stdin never hangs the scaffold."""
283
+ q = _paint(_glyph("?", "?"), _ACCENT, "1")
284
+ print(f"{q} {_bold(_safe(title))}")
285
+ for i, (_value, label, hint) in enumerate(options):
286
+ num = _paint(f"{i + 1})", _ACCENT2)
287
+ lab = _bold(label) if i == default else label
288
+ tail = f" {_dim(_safe(hint))}" if hint else ""
289
+ mark = _paint(" (default)", _GREEN) if i == default else ""
290
+ print(f" {num} {_safe(lab)}{tail}{mark}")
291
+ pointer = _paint(_glyph("›", ">"), _ACCENT2) # noqa: RUF001 (the glyph is the point)
292
+ for _ in range(5):
293
+ try:
294
+ raw = input(f"{pointer} ").strip()
295
+ except EOFError:
296
+ print()
297
+ return options[default][0]
298
+ if not raw:
299
+ return options[default][0]
300
+ if raw.isdigit():
301
+ idx = int(raw) - 1
302
+ if 0 <= idx < len(options):
303
+ return options[idx][0]
304
+ print(note(f"enter 1-{len(options)}, or press enter for the default"))
305
+ return options[default][0]
306
+
307
+
276
308
  def money(value: float, decimals: int = 4) -> str:
277
309
  return _paint(f"${value:.{decimals}f}", _TEAL)
278
310
 
@@ -110,12 +110,13 @@ def _effective_worker_env(spec=None) -> dict[str, str]:
110
110
  # Chalk is published to PUBLIC PyPI on every version bump (chalk .github/workflows/publish.yml).
111
111
  # Pin the exact PUBLIC version so worker + kernel-cache-bake pods install with NO GitHub auth — the
112
112
  # chalk repo is INTERNAL, so a git+https default made installs fail wherever GITHUB_TOKEN is absent
113
- # (bake pod, tokenless workers). freesolo-chalk 0.5.0 = chalk PR #21 fafe167 (standalone, Liger fully
114
- # replaced, + GRPO op + LoRA grad-gate). Bump DEFAULT_CHALK_VERSION when the merged kernel surface moves.
115
- DEFAULT_CHALK_VERSION = "0.5.1"
113
+ # (bake pod, tokenless workers). freesolo-chalk 0.5.2 = chalk dev->main sync #44 (standalone, Liger
114
+ # fully replaced; adds arch-TUNED gdn_gated_rmsnorm + lora on sm89/sm90/sm100, MoE grouped-GEMM,
115
+ # serving surface, MiniCPM/Llama kernels). Bump DEFAULT_CHALK_VERSION when the merged kernel surface moves.
116
+ DEFAULT_CHALK_VERSION = "0.5.2"
116
117
  DEFAULT_CHALK_SPEC = f"freesolo-chalk=={DEFAULT_CHALK_VERSION}"
117
118
  # Provenance only (kernel-cache fingerprint / traceability): the chalk commit this version was cut from.
118
- LATEST_CHALK_MAIN_SHA = "fafe167158eb3b7c947e7182ea4eddc351e4ca7d"
119
+ LATEST_CHALK_MAIN_SHA = "37b2fb9e1a123ceb902ba6ffc4ed182182c6e7d7"
119
120
 
120
121
 
121
122
  def chalk_extra_pip(spec=None) -> list[str]:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "freesolo-flash-dev"
3
- version = "0.2.41"
3
+ version = "0.2.42"
4
4
  description = "Flash — managed LoRA post-training (SFT/GRPO) 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).
@@ -106,7 +106,7 @@ artifacts = ["flash/py.typed"]
106
106
  # auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
107
107
  # PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
108
108
  # dev-channel release = bump this (and [project].version) and merge to `dev`.
109
- version = "0.2.41"
109
+ version = "0.2.42"
110
110
 
111
111
  [tool.pytest.ini_options]
112
112
  pythonpath = ["."]
@@ -8,6 +8,7 @@ the remaining commands are covered without a server.
8
8
  from __future__ import annotations
9
9
 
10
10
  import io
11
+ import types
11
12
 
12
13
  import pytest
13
14
 
@@ -474,6 +475,108 @@ def test_env_setup_scaffolds_grpo_and_sft_configs(monkeypatch, tmp_path, capsys)
474
475
  assert "TRAINING.md" in out
475
476
 
476
477
 
478
+ def test_env_setup_default_omits_reasoning(monkeypatch, tmp_path) -> None:
479
+ # Non-interactive (pytest stdin is not a tty) with no flags stays on today's scaffold: no
480
+ # reasoning knobs land in either config.
481
+ monkeypatch.chdir(tmp_path)
482
+ assert _run(["env", "setup"]) == 0
483
+ rl = (tmp_path / "configs/rl.toml").read_text()
484
+ sft = (tmp_path / "configs/sft.toml").read_text()
485
+ assert "thinking = true" not in rl
486
+ assert "thinking = true" not in sft
487
+ assert "max_tokens" not in rl
488
+ assert "EnvironmentSingleTurn" in (tmp_path / "environment.py").read_text()
489
+
490
+
491
+ def test_env_setup_reasoning_flag_enables_thinking(monkeypatch, tmp_path) -> None:
492
+ monkeypatch.chdir(tmp_path)
493
+ assert _run(["env", "setup", "--reasoning"]) == 0
494
+ rl = (tmp_path / "configs/rl.toml").read_text()
495
+ sft = (tmp_path / "configs/sft.toml").read_text()
496
+ assert "thinking = true" in rl
497
+ assert "thinking = true" in sft
498
+ # GRPO raises the generation budget so reasoning does not truncate the answer.
499
+ assert "max_tokens = 2048" in rl
500
+ # SFT can't share a token budget it doesn't generate; it gets the gold think-tag guidance instead.
501
+ assert "warn_missing_think_tags" in sft
502
+ assert "max_tokens" not in sft
503
+
504
+
505
+ def test_env_setup_no_reasoning_flag_is_explicit_off(monkeypatch, tmp_path) -> None:
506
+ monkeypatch.chdir(tmp_path)
507
+ assert _run(["env", "setup", "--no-reasoning"]) == 0
508
+ assert "thinking = true" not in (tmp_path / "configs/rl.toml").read_text()
509
+
510
+
511
+ def test_env_setup_multi_turn_flag_scaffolds_multiturn(monkeypatch, tmp_path) -> None:
512
+ monkeypatch.chdir(tmp_path)
513
+ assert _run(["env", "setup", "--multi-turn"]) == 0
514
+ assert "EnvironmentMultiTurn" in (tmp_path / "environment.py").read_text()
515
+ assert "secret whole number" in (tmp_path / "dataset/train.jsonl").read_text()
516
+
517
+
518
+ def test_env_setup_interactive_survey_picks_multi_and_reasoning(monkeypatch, tmp_path) -> None:
519
+ # A real terminal: the two survey questions are asked and answered "2" (multi-turn) then
520
+ # "2" (reasoning). FLASH_STYLE forces the themed path; a fake stdin reports a tty; input()
521
+ # is stubbed so no real keypress is read. CI is cleared so the guard doesn't force defaults.
522
+ monkeypatch.chdir(tmp_path)
523
+ monkeypatch.delenv("CI", raising=False)
524
+ monkeypatch.setenv("FLASH_STYLE", "1")
525
+ monkeypatch.setattr("sys.stdin", types.SimpleNamespace(isatty=lambda: True))
526
+ answers = iter(["2", "2"])
527
+ monkeypatch.setattr("builtins.input", lambda *a, **k: next(answers))
528
+ assert _run(["env", "setup"]) == 0
529
+ assert "EnvironmentMultiTurn" in (tmp_path / "environment.py").read_text()
530
+ rl = (tmp_path / "configs/rl.toml").read_text()
531
+ assert "thinking = true" in rl
532
+ assert "max_tokens = 2048" in rl
533
+
534
+
535
+ def test_env_setup_interactive_enter_takes_defaults(monkeypatch, tmp_path) -> None:
536
+ # Pressing enter (empty answer) at both questions selects the marked defaults: single-turn,
537
+ # no reasoning — identical to the non-interactive scaffold.
538
+ monkeypatch.chdir(tmp_path)
539
+ monkeypatch.delenv("CI", raising=False)
540
+ monkeypatch.setenv("FLASH_STYLE", "1")
541
+ monkeypatch.setattr("sys.stdin", types.SimpleNamespace(isatty=lambda: True))
542
+ monkeypatch.setattr("builtins.input", lambda *a, **k: "")
543
+ assert _run(["env", "setup"]) == 0
544
+ env_py = (tmp_path / "environment.py").read_text()
545
+ assert "EnvironmentSingleTurn" in env_py
546
+ assert "EnvironmentMultiTurn" not in env_py
547
+ assert "thinking = true" not in (tmp_path / "configs/rl.toml").read_text()
548
+
549
+
550
+ def test_env_setup_under_ci_never_prompts(monkeypatch, tmp_path) -> None:
551
+ # Even with a tty and themed output, CI=true must fall back to defaults instead of blocking on
552
+ # a prompt. input() raises so a regression (actually prompting) fails loudly.
553
+ monkeypatch.chdir(tmp_path)
554
+ monkeypatch.setenv("CI", "true")
555
+ monkeypatch.setenv("FLASH_STYLE", "1")
556
+ monkeypatch.setattr("sys.stdin", types.SimpleNamespace(isatty=lambda: True))
557
+
558
+ def _boom(*a, **k):
559
+ raise AssertionError("prompted under CI")
560
+
561
+ monkeypatch.setattr("builtins.input", _boom)
562
+ assert _run(["env", "setup"]) == 0
563
+ assert "EnvironmentSingleTurn" in (tmp_path / "environment.py").read_text()
564
+ assert "thinking = true" not in (tmp_path / "configs/rl.toml").read_text()
565
+
566
+
567
+ def test_env_setup_reasoning_flag_warns_when_configs_exist(monkeypatch, tmp_path, capsys) -> None:
568
+ # First scaffold (no reasoning), then re-run with --reasoning: the existing configs win and the
569
+ # command warns instead of silently ignoring the flag or writing mismatched configs.
570
+ monkeypatch.chdir(tmp_path)
571
+ assert _run(["env", "setup"]) == 0
572
+ capsys.readouterr()
573
+ assert _run(["env", "setup", "--reasoning"]) == 0
574
+ err = capsys.readouterr().err
575
+ assert "existing configs are no reasoning" in err
576
+ assert "ignoring --reasoning" in err
577
+ assert "thinking = true" not in (tmp_path / "configs/rl.toml").read_text()
578
+
579
+
477
580
  def test_unknown_run_errors_surface_as_nonzero_exit(monkeypatch, capsys) -> None:
478
581
  from flash.client import ApiError
479
582
 
@@ -166,7 +166,7 @@ def test_chalk_extra_pip_defaults_to_latest_main_without_spec(monkeypatch):
166
166
  assert chalk_extra_pip() == [DEFAULT_CHALK_SPEC]
167
167
  # public PyPI pin so tokenless bake/worker pods can pip-install (chalk repo is internal)
168
168
  assert DEFAULT_CHALK_SPEC.startswith("freesolo-chalk==")
169
- assert DEFAULT_CHALK_SPEC == "freesolo-chalk==0.5.1"
169
+ assert DEFAULT_CHALK_SPEC == "freesolo-chalk==0.5.2"
170
170
 
171
171
 
172
172
  def test_chalk_extra_pip_adds_spec_when_set(monkeypatch):
@@ -1024,7 +1024,7 @@ wheels = [
1024
1024
 
1025
1025
  [[package]]
1026
1026
  name = "freesolo-flash"
1027
- version = "0.2.39"
1027
+ version = "0.2.41"
1028
1028
  source = { editable = "." }
1029
1029
 
1030
1030
  [package.optional-dependencies]