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.
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/Dockerfile.worker +1 -1
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/PKG-INFO +4 -4
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/catalog.py +13 -20
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/__init__.py +17 -14
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/commands.py +99 -47
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/envpush.py +9 -11
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/render.py +22 -6
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/training_doc.py +8 -7
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/http.py +55 -28
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/vram.py +52 -3
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/adapter.py +14 -17
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/hf.py +123 -37
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/__init__.py +0 -4
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/rl.py +3 -3
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/sft.py +1 -1
- freesolo_flash_dev-0.2.36/flash/envs/adapter.py +447 -0
- freesolo_flash_dev-0.2.34/flash/envs/adapter.py → freesolo_flash_dev-0.2.36/flash/envs/loader.py +98 -399
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/pull.py +1 -1
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/registry.py +1 -1
- freesolo_flash_dev-0.2.36/flash/lora_rank.py +193 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/train/deps.py +1 -1
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/train/endpoints.py +64 -29
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/__init__.py +127 -12
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/checkpoints.py +64 -13
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/deploy.py +88 -19
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/schema/__init__.py +60 -5
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/deploy.py +175 -32
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_runtime.py +23 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/app.py +19 -1
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/envs.py +3 -4
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/runs.py +1 -1
- freesolo_flash_dev-0.2.36/flash/server/routes/serving.py +643 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/pyproject.toml +6 -6
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/conftest.py +29 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_agent_flash_cli_contract.py +2 -4
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cancel_remote.py +123 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_catalog_consistency.py +18 -24
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_checkpoints.py +167 -2
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_commands.py +98 -15
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_render_theme.py +3 -5
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_client.py +31 -42
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_client_server_integration.py +6 -0
- freesolo_flash_dev-0.2.36/tests/test_env_cache_evict.py +70 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_pull.py +1 -1
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_rate_limit_resolve.py +8 -8
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_github_urlopen_retry.py +1 -1
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_gpus.py +18 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_grpo_params.py +55 -109
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_jobs.py +448 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_kv_util.py +8 -0
- freesolo_flash_dev-0.2.36/tests/test_lora_rank_preflight.py +97 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_orchestrator_flash.py +3 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_serve.py +52 -11
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_server_api.py +332 -13
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_serving_contract.py +191 -3
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_spec_and_validation.py +6 -6
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_verifiers.py +138 -15
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_vl_warmstart_recombine.py +11 -10
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_warmstart_cross_repo.py +21 -4
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/uv.lock +8 -8
- freesolo_flash_dev-0.2.34/flash/server/routes/serving.py +0 -348
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.dockerignore +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.env.example +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/.gitignore +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/Dockerfile +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/LICENSE +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/README.md +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/README.md +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/generate.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/index.html +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/preview.png +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/cli-style/themed-errors.png +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/docs/kernel-cache.md +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_channel.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_logging.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/config.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/lambdalabs/train.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/preload.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/py.typed +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/db.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/flash/spec.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_b200_rollout_opt.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_export.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_grpo_sleep_gate.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_version.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_vl_weight_sync.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.34 → freesolo_flash_dev-0.2.36}/tests/test_worker_stack.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
"
|
|
120
|
-
"Qwen/Qwen3.5-
|
|
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=
|
|
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=
|
|
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=
|
|
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="
|
|
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=
|
|
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="
|
|
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=
|
|
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
|
|
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=
|
|
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
|
|
296
|
-
serving paths currently allow rank
|
|
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(
|
|
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
|
-
"--
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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=
|
|
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
|
-
|
|
491
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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}
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
191
|
+
"""Normalize only the NAME segment; a namespace prefix is passed through verbatim.
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
|
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
|
-
|
|
206
|
-
name
|
|
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"{
|
|
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:
|
|
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
|
-
(
|
|
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}
|
|
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(
|
|
558
|
+
("endpoint", _paint(endpoint, _GREEN) if endpoint else None),
|
|
547
559
|
("gpu", dep.get("gpu")),
|
|
548
|
-
("url", _paint(
|
|
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
|
|
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
|
|
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
|
-
#
|
|
354
|
-
#
|
|
355
|
-
init_from_adapter = "
|
|
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
|
|
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
|
|
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.
|