freesolo-flash-dev 1.1.68__tar.gz → 1.1.70__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-1.1.68 → freesolo_flash_dev-1.1.70}/PKG-INFO +1 -1
- freesolo_flash_dev-1.1.70/flash/adapters/artifacts.py +141 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/adapters/lora_rank.py +31 -11
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/eval.py +27 -36
- freesolo_flash_dev-1.1.70/flash/cli/commands/env/eval_args.py +43 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/retained.py +13 -3
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/setup.py +9 -5
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/__init__.py +5 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/io/hf.py +15 -5
- freesolo_flash_dev-1.1.70/flash/engine/worker/model/lora.py +118 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/sft_train.py +9 -1
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/multiturn_validation.py +8 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/adapter.py +4 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/identity.py +20 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/loader.py +8 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/artifacts/hf.py +31 -9
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/attempts.py +10 -4
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/results/checkpoints.py +9 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/supervise/seed_submission.py +76 -5
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/adapter_check.py +22 -6
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/export.py +11 -4
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/envs.py +16 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/projects.py +53 -6
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/teacher/retry_contract.py +32 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/pyproject.toml +2 -2
- freesolo_flash_dev-1.1.70/tests/test_adapter_shard_completeness.py +283 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_dev_channel.py +55 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_evaluations.py +48 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_list_hub.py +48 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_export.py +8 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_github_urlopen_retry.py +19 -7
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_jobs.py +3 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_lora_rank_coverage.py +1 -1
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_lora_rank_preflight.py +2 -2
- freesolo_flash_dev-1.1.70/tests/test_opd_multiturn_eos_boundary.py +75 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_opd_resume_safety.py +96 -2
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_projects.py +73 -1
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_sft_train.py +33 -1
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/uv.lock +1 -1
- freesolo_flash_dev-1.1.68/flash/adapters/artifacts.py +0 -55
- freesolo_flash_dev-1.1.68/flash/engine/worker/model/lora.py +0 -97
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.dockerignore +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.env.example +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/CODEOWNERS +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/.gitignore +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/CHANGELOG.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/Dockerfile +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/LICENSE +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/NOTICE +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/README.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/SELF_HOSTING.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/deploy/infisical/README.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/deploy/infisical/entrypoint.sh +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/docker/extract_cudart_fix.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/_internal/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/_internal/channel.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/_internal/diagnostics.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/_internal/fileio.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/_internal/logging.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/_internal/paths.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/adapters/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/deploy.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/episode.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/imports.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/list.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/push.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/env/test.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/traces.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/commands/train_cost.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/scaffold/TRAINING.md +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/scaffold/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/ui/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/ui/cost.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/ui/env_panels.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/ui/heartbeat.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/ui/render.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/ui/tables.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cli/ui/tty.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/freesolo_api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/shapes.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/client/streaming.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/content/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/content/multimodal.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/content/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/content/thinking.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/core/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/core/catalog.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/core/spec.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/plan/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/plan/kv_sizing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/plan/model_config_probe.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/plan/recipe.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/plan/steps.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/plan/vram.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/profiling/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/profiling/dataset_profile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/profiling/reward_profile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/profiling/sft_workload.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/profiling/tokenizer.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/profiling/workload_profile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/result/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/result/accounting.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/result/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/backend_common.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/entry/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/entry/opd.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/entry/rl.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/entry/sft.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/io/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/io/heartbeat.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/io/prefetch.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/io/wandb_log.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/model/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/model/adapter.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/model/decoding.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/model/packing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/opd_train.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/opd_train_runner.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/rl_train.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/rl_train_runner.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/runtime/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/runtime/rng.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/score_batcher.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/sft_train_runner.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/teacher/client.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/teacher/encoding.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/core/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/core/child/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/core/child/glue.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/finalize.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/batching.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/bridge.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/child/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/child/bridge.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/child/plugin.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/child/structured.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/failures.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/gkd.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/overrides.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/prompts.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/scoring.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/opd/validation.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/child/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/child/plugin.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/config.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/inputs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/multi_turn.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/scoring.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/shims.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/single_turn.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/rl/verl_config.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/sft/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/sft/checkpoints.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/train/sft/config.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/verl/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/verl/capabilities.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/verl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/verl/child_io.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/verl/diagnostics.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker/verl/parallelism.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/cache_security.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/dataset_selection.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/namespace_listing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/package/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/package/limits.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/package/unpack.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/auth.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/bootstrap.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/bootstrap_pip.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/deadline.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/http.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/instance.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/poll.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/poll_instance.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/provider.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/_lifecycle/worker.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/artifacts/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/artifacts/preload_runpod.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/artifacts/weight_cache.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/fit_errors.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/auth.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/gpus.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/jobs/reap.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/lambda_/pricing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/job_execution.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/resources.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/serverless/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/runpod/serverless/endpoints.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/artifacts.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/costs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/deadlines.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/preparation.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/reconciliation.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/results/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/results/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/status.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/submit.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/supervise/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/supervise/attach.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/supervise/deploy.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/supervise/lifecycle.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/supervise/recovery.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/supervise/transitions.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/runner/weight_cache.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/errors.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/streaming.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/thinking.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/billing/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/billing/charges.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/billing/retry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/checkpoints.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/environment_registry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/reconcile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/run_registry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/teacher_broker.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/teacher_errors.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/domain/teacher_requests.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/platform/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/platform/auth.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/platform/db.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/platform/deps.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/platform/internal_client.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/platform/locks.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/platform/runtime.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/serving_completion.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/serving_revisions.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/serving_smoke.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/flash/teacher/limits.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/scripts/check_file_size.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/scripts/check_function_size.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/scripts/check_verl_pin_exists.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/_helpers/profile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/_helpers/teacher.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_build_context_contract.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_catalog_only_models.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_client_import_purity.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_config_env_vars.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_dataset_profile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_list_api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_list_cli.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_freesolo_api_transport.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_infisical_secrets.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_opd_train.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_parasail_teacher.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_reward_profile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_rl_train.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_rollout_profile_quote.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_rollout_workload_profile.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_sft_workload.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_step_floor.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_teacher_broker.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_teacher_encoding_contract.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_type_comment_prose.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_worker_thinking.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_workflow_contracts.py +0 -0
- {freesolo_flash_dev-1.1.68 → freesolo_flash_dev-1.1.70}/tests/test_workload_profile.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.70
|
|
4
4
|
Summary: Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/freesolo-co/flash
|
|
6
6
|
Project-URL: Repository, https://github.com/freesolo-co/flash
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Artifact filenames the worker writes and the control plane reads.
|
|
2
|
+
|
|
3
|
+
Every name here crosses a machine boundary: the worker uploads under it, the control plane fetches
|
|
4
|
+
by it, and the two never share a call stack to check. Spelling one on each side makes them agree by
|
|
5
|
+
coincidence, so they are defined once, here.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# The PEFT adapter weights file a deployable adapter must carry. Modern saves use safetensors,
|
|
9
|
+
# but older PEFT/default settings may emit adapter_model.bin.
|
|
10
|
+
ADAPTER_WEIGHT_FILES = ("adapter_model.safetensors", "adapter_model.bin")
|
|
11
|
+
|
|
12
|
+
# A PEFT save past its shard size splits the weights across `adapter_model-0000N-of-0000M.<ext>`
|
|
13
|
+
# beside an `adapter_model.<ext>.index.json` mapping every tensor key to the shard holding it.
|
|
14
|
+
ADAPTER_SHARD_PREFIX = "adapter_model-"
|
|
15
|
+
ADAPTER_WEIGHT_SUFFIXES = (".safetensors", ".bin")
|
|
16
|
+
ADAPTER_WEIGHT_INDEX_FILES = tuple(f"{name}.index.json" for name in ADAPTER_WEIGHT_FILES)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def is_adapter_weight_filename(filename: str) -> bool:
|
|
20
|
+
"""True for every adapter weight file shape the pipeline accepts, single-file or sharded.
|
|
21
|
+
|
|
22
|
+
One predicate for the same reason the filenames above are defined once: serving validation and
|
|
23
|
+
the exporter never share a call stack, and each spelling the shapes for itself makes them agree
|
|
24
|
+
by coincidence. A disagreement fails silently, because validation accepts a shape the exporter
|
|
25
|
+
skips and the export then ships weights peft loads as a no-op.
|
|
26
|
+
|
|
27
|
+
Filename shape only. Whether a SET of these files is loadable is a different question, because a
|
|
28
|
+
lone shard is not: see :func:`has_loadable_adapter_weights`.
|
|
29
|
+
"""
|
|
30
|
+
name = filename.rsplit("/", 1)[-1]
|
|
31
|
+
if name in ADAPTER_WEIGHT_FILES:
|
|
32
|
+
return True
|
|
33
|
+
return name.startswith(ADAPTER_SHARD_PREFIX) and name.endswith(ADAPTER_WEIGHT_SUFFIXES)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def loadable_adapter_weight_files(filenames) -> list[str]:
|
|
37
|
+
"""The files peft would load out of ``filenames``, or ``[]`` when it could load none.
|
|
38
|
+
|
|
39
|
+
The set, not the filename, is what decides this, and the difference is the whole point. peft
|
|
40
|
+
binds one representation per suffix -- the single ``adapter_model.<ext>`` when present, otherwise
|
|
41
|
+
the shards -- and it discovers the sharded form ONLY through ``adapter_model.<ext>.index.json``.
|
|
42
|
+
A directory holding ``adapter_model-00001-of-00002.safetensors`` and no index therefore has no
|
|
43
|
+
loadable representation at all: nothing tells peft the sharded form exists, or which shards
|
|
44
|
+
complete it.
|
|
45
|
+
|
|
46
|
+
Accepting that orphan is what let an incomplete upload pass validation. Export then falls back to
|
|
47
|
+
shipping every matching shard when it finds no index, so deployment and export both "succeeded"
|
|
48
|
+
while producing weights peft loads as a no-op -- the silent-disagreement failure this module
|
|
49
|
+
exists to prevent, arriving one level up at the set instead of at the name.
|
|
50
|
+
|
|
51
|
+
A partial shard set is rejected for the same reason: the index names the complete set, so a
|
|
52
|
+
listing missing one of its members cannot be loaded either. Residue carrying a second shard total
|
|
53
|
+
also fails closed. Filenames cannot reveal which total the index references, and guessing risks
|
|
54
|
+
binding stale weights; cleaning the residue or re-uploading makes the representation decidable.
|
|
55
|
+
|
|
56
|
+
Returned in peft's own precedence order, so the caller that reads tensor keys reads exactly the
|
|
57
|
+
files the serving engine will.
|
|
58
|
+
"""
|
|
59
|
+
names = {str(name).rsplit("/", 1)[-1] for name in filenames}
|
|
60
|
+
for suffix in ADAPTER_WEIGHT_SUFFIXES:
|
|
61
|
+
single = f"adapter_model{suffix}"
|
|
62
|
+
if single in names:
|
|
63
|
+
return [single]
|
|
64
|
+
referenced = _index_shard_names(names, suffix)
|
|
65
|
+
if referenced:
|
|
66
|
+
return sorted(referenced)
|
|
67
|
+
return []
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def has_loadable_adapter_weights(filenames) -> bool:
|
|
71
|
+
"""True when ``filenames`` holds weights peft can actually load."""
|
|
72
|
+
return bool(loadable_adapter_weight_files(filenames))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _index_shard_names(names: set[str], suffix: str) -> set[str]:
|
|
76
|
+
"""The shard names an index for ``suffix`` would have to be accompanied by, from names alone.
|
|
77
|
+
|
|
78
|
+
Derived from the ``adapter_model-{k}-of-{n}.<ext>`` convention rather than by reading the index
|
|
79
|
+
file, because every caller here works from a LISTING: serving validates against a remote repo
|
|
80
|
+
listing and the worker against a directory listing, and neither should have to download and
|
|
81
|
+
parse json to answer "is this set complete". The exporter, which already has the files locally,
|
|
82
|
+
still reads the real ``weight_map`` -- that is the authority on which shards are live.
|
|
83
|
+
|
|
84
|
+
Empty when no index is present, the sole candidate shard set is incomplete, or more than one
|
|
85
|
+
candidate total appears. The last case is genuinely undecidable from filenames alone: the index
|
|
86
|
+
names exactly one set but the listing cannot say which, so rejecting loudly is safer than silently
|
|
87
|
+
serving stale weights.
|
|
88
|
+
"""
|
|
89
|
+
if f"adapter_model{suffix}.index.json" not in names:
|
|
90
|
+
return set()
|
|
91
|
+
totals = set()
|
|
92
|
+
oversized_total = False
|
|
93
|
+
for name in names:
|
|
94
|
+
if not name.startswith(ADAPTER_SHARD_PREFIX) or not name.endswith(suffix):
|
|
95
|
+
continue
|
|
96
|
+
stem = name[len(ADAPTER_SHARD_PREFIX) : -len(suffix)]
|
|
97
|
+
shard, sep, total = stem.partition("-of-")
|
|
98
|
+
if not (sep and shard.isdigit() and total.isdigit()):
|
|
99
|
+
continue
|
|
100
|
+
parsed_total = int(total)
|
|
101
|
+
if parsed_total <= 0:
|
|
102
|
+
continue
|
|
103
|
+
if parsed_total > len(names):
|
|
104
|
+
# this total cannot be complete, but it still proves the listing contains residue from a
|
|
105
|
+
# different save. keep that ambiguity evidence without materializing an unbounded set.
|
|
106
|
+
oversized_total = True
|
|
107
|
+
continue
|
|
108
|
+
totals.add((total, len(shard)))
|
|
109
|
+
if oversized_total or len(totals) != 1:
|
|
110
|
+
return set()
|
|
111
|
+
total, width = next(iter(totals))
|
|
112
|
+
candidate = {
|
|
113
|
+
f"{ADAPTER_SHARD_PREFIX}{index:0{width}d}-of-{total}{suffix}"
|
|
114
|
+
for index in range(1, int(total) + 1)
|
|
115
|
+
}
|
|
116
|
+
return candidate if candidate <= names else set()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# The largest attempt identity any artifact name may carry. An attempt number reaches a filename and
|
|
120
|
+
# an HF path, so it is bounded rather than merely nonnegative: an unbounded int would still format,
|
|
121
|
+
# and the resulting name is the one thing a later reader has to match exactly.
|
|
122
|
+
MAX_ATTEMPT_ID = (1 << 63) - 1
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def attempt_scoped_artifact_name(kind: str, phase: str, attempt: int) -> str:
|
|
126
|
+
"""The name of one per-phase, per-attempt worker text artifact.
|
|
127
|
+
|
|
128
|
+
The worker uploads these and the control plane reads them back, so the format is a contract
|
|
129
|
+
between two processes that never share a call stack. It lives here, beside the adapter filenames,
|
|
130
|
+
because a reader that spells the name for itself agrees with the writer only by coincidence --
|
|
131
|
+
and the failure is silent: a missing artifact reads as "the worker uploaded nothing", which is
|
|
132
|
+
exactly what it looks like when the worker crashed. That is the case these files exist to explain.
|
|
133
|
+
|
|
134
|
+
Attempt-scoped because ``hf_prefix()`` is per-RUN, not per-attempt: without the suffix a retry
|
|
135
|
+
would overwrite the attempt that actually reproduced the failure.
|
|
136
|
+
"""
|
|
137
|
+
if isinstance(attempt, bool) or not isinstance(attempt, int):
|
|
138
|
+
raise ValueError("attempt must be a nonnegative integer")
|
|
139
|
+
if attempt < 0 or attempt > MAX_ATTEMPT_ID:
|
|
140
|
+
raise ValueError("attempt must be a bounded nonnegative integer")
|
|
141
|
+
return f"{kind}_{phase}_attempt{attempt}.txt"
|
|
@@ -189,8 +189,17 @@ def adapter_artifact_identity(
|
|
|
189
189
|
token: str | None = None,
|
|
190
190
|
revision: str | None = None,
|
|
191
191
|
) -> AdapterArtifactIdentity:
|
|
192
|
-
"""Bind adapter config semantics and
|
|
193
|
-
|
|
192
|
+
"""Bind adapter config semantics and the required weight objects' immutable metadata.
|
|
193
|
+
|
|
194
|
+
Binds whatever peft would load, which for a save past its shard size is the complete
|
|
195
|
+
index-referenced shard set rather than a single file. Asking for the two single-file names by
|
|
196
|
+
path could not see a sharded adapter at all, so warm-starting from one failed here -- at
|
|
197
|
+
submission, before the worker that would have loaded it ever ran.
|
|
198
|
+
|
|
199
|
+
A single-file adapter's digest is unchanged by that: it still binds exactly its one name and
|
|
200
|
+
identity, so an in-flight run's stored identity still compares equal.
|
|
201
|
+
"""
|
|
202
|
+
from flash.adapters.artifacts import loadable_adapter_weight_files
|
|
194
203
|
|
|
195
204
|
resolved = resolve_adapter_ref(adapter_ref)
|
|
196
205
|
if resolved is None:
|
|
@@ -198,26 +207,37 @@ def adapter_artifact_identity(
|
|
|
198
207
|
repo, prefix = resolved
|
|
199
208
|
config_bytes = _canonical_config_bytes(config)
|
|
200
209
|
config_sha256 = hashlib.sha256(config_bytes).hexdigest()
|
|
201
|
-
|
|
210
|
+
folder = f"{prefix}/adapter"
|
|
202
211
|
try:
|
|
203
212
|
from huggingface_hub import HfApi
|
|
204
213
|
|
|
205
|
-
infos =
|
|
206
|
-
|
|
214
|
+
infos = list(
|
|
215
|
+
HfApi(token=token).list_repo_tree(
|
|
216
|
+
repo_id=repo,
|
|
217
|
+
path_in_repo=folder,
|
|
218
|
+
repo_type="dataset",
|
|
219
|
+
recursive=False,
|
|
220
|
+
revision=revision,
|
|
221
|
+
)
|
|
207
222
|
)
|
|
208
223
|
except Exception as exc:
|
|
209
224
|
raise ValueError("could not verify source adapter weight identity") from exc
|
|
210
225
|
by_name = {str(getattr(info, "path", "")).rsplit("/", 1)[-1]: info for info in infos}
|
|
211
|
-
selected =
|
|
212
|
-
if selected
|
|
226
|
+
selected = loadable_adapter_weight_files(by_name)
|
|
227
|
+
if not selected:
|
|
213
228
|
raise ValueError("source adapter has no required weight file")
|
|
214
|
-
|
|
215
|
-
|
|
229
|
+
identities = [_file_identity(by_name[name]) for name in selected]
|
|
230
|
+
# every selected object, because a sharded adapter's content is the union of its shards: binding
|
|
231
|
+
# only the first would let a later attempt rewrite the rest and still compare equal.
|
|
232
|
+
bound = "\0".join(
|
|
233
|
+
f"{name}\0{identity}" for name, identity in zip(selected, identities, strict=True)
|
|
234
|
+
)
|
|
235
|
+
payload = f"v1\0{config_sha256}\0{bound}".encode()
|
|
216
236
|
return AdapterArtifactIdentity(
|
|
217
237
|
digest=hashlib.sha256(payload).hexdigest(),
|
|
218
238
|
config_sha256=config_sha256,
|
|
219
|
-
weight_filename=selected,
|
|
220
|
-
weight_identity=
|
|
239
|
+
weight_filename=",".join(selected),
|
|
240
|
+
weight_identity=",".join(identities),
|
|
221
241
|
)
|
|
222
242
|
|
|
223
243
|
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import argparse
|
|
6
|
-
import math
|
|
7
5
|
import queue
|
|
8
6
|
import tempfile
|
|
9
7
|
import threading
|
|
@@ -12,6 +10,12 @@ from datetime import UTC, datetime
|
|
|
12
10
|
from pathlib import Path
|
|
13
11
|
|
|
14
12
|
from flash._internal.channel import CLI_NAME
|
|
13
|
+
from flash.cli.commands.env.eval_args import (
|
|
14
|
+
_MAX_CONCURRENCY,
|
|
15
|
+
bounded_concurrency,
|
|
16
|
+
finite_float,
|
|
17
|
+
positive_int,
|
|
18
|
+
)
|
|
15
19
|
from flash.cli.commands.env.push import _err
|
|
16
20
|
from flash.cli.commands.env.test import _env_params, _evaluation_example
|
|
17
21
|
from flash.cli.ui import render
|
|
@@ -25,36 +29,6 @@ from flash.envs.evaluations import (
|
|
|
25
29
|
validate_evaluation_cases,
|
|
26
30
|
)
|
|
27
31
|
|
|
28
|
-
_MAX_CONCURRENCY = 32
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def positive_int(value: str) -> int:
|
|
32
|
-
parsed = int(value)
|
|
33
|
-
if parsed < 1:
|
|
34
|
-
raise argparse.ArgumentTypeError("must be at least 1")
|
|
35
|
-
return parsed
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def finite_float(value: str) -> float:
|
|
39
|
-
"""A temperature the chat route will accept.
|
|
40
|
-
|
|
41
|
-
Reject non-finite or negative values before they become one paid rejection per case.
|
|
42
|
-
The nonnegative floor matches `flash/schema/__init__.py`.
|
|
43
|
-
"""
|
|
44
|
-
parsed = float(value)
|
|
45
|
-
if not math.isfinite(parsed):
|
|
46
|
-
raise argparse.ArgumentTypeError(f"must be a finite number, got {value}")
|
|
47
|
-
if parsed < 0.0:
|
|
48
|
-
raise argparse.ArgumentTypeError(f"must be at least 0.0, got {value}")
|
|
49
|
-
return parsed
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def bounded_concurrency(value: str) -> int:
|
|
53
|
-
parsed = positive_int(value)
|
|
54
|
-
if parsed > _MAX_CONCURRENCY:
|
|
55
|
-
raise argparse.ArgumentTypeError(f"must be at most {_MAX_CONCURRENCY}")
|
|
56
|
-
return parsed
|
|
57
|
-
|
|
58
32
|
|
|
59
33
|
def _generation_error(case_id: str, message: str) -> EvalResult:
|
|
60
34
|
return EvalResult(
|
|
@@ -159,13 +133,17 @@ def _scored_response(response: str, *, thinking: bool) -> str:
|
|
|
159
133
|
"""The response as a scorer should see it, matching what training grades.
|
|
160
134
|
|
|
161
135
|
Strip reasoning only for `thinking` runs; raw reasoning mis-grades them, while unconditional
|
|
162
|
-
stripping can truncate non-thinking answers that mention `<think>`.
|
|
136
|
+
stripping can truncate non-thinking answers that mention `<think>`. An already-structured value
|
|
137
|
+
passes through: re-deriving it from its own answer-only string destroys the raw and thinking
|
|
138
|
+
views only its producer had the generation to build.
|
|
163
139
|
"""
|
|
164
140
|
if not thinking:
|
|
165
141
|
return response
|
|
166
142
|
from flash.content.thinking import strip_think, thinking_text
|
|
167
143
|
from flash.envs.adapter import _ScoredResponseText
|
|
168
144
|
|
|
145
|
+
if isinstance(response, _ScoredResponseText):
|
|
146
|
+
return response
|
|
169
147
|
answer = strip_think(response)
|
|
170
148
|
return _ScoredResponseText(
|
|
171
149
|
answer if isinstance(answer, str) else response,
|
|
@@ -194,22 +172,28 @@ def _score_case(
|
|
|
194
172
|
`state_keyword` says which way that suite's signature can take it -- `**kwargs` and
|
|
195
173
|
keyword-only scorers reject a third positional, `*args` scorers reject the keyword -- so the
|
|
196
174
|
caller decides, having read the signature.
|
|
175
|
+
|
|
176
|
+
The scorer grades the stripped answer; the RESULT records the raw generation. Stripping for the
|
|
177
|
+
scorer must not shorten what is recorded, on the error path least of all -- a failed case is
|
|
178
|
+
when the reasoning that explains it matters most.
|
|
197
179
|
"""
|
|
180
|
+
recorded_response = response
|
|
198
181
|
try:
|
|
199
182
|
scored_text = _scored_response(response, thinking=thinking)
|
|
183
|
+
recorded_response = getattr(scored_text, "raw", response)
|
|
200
184
|
if state is None:
|
|
201
185
|
scored = suite.score(case, scored_text)
|
|
202
186
|
elif state_keyword:
|
|
203
187
|
scored = suite.score(case, scored_text, state=state)
|
|
204
188
|
else:
|
|
205
189
|
scored = suite.score(case, scored_text, state)
|
|
206
|
-
return normalize_eval_result(case,
|
|
190
|
+
return normalize_eval_result(case, recorded_response, scored, case_id=case_id)
|
|
207
191
|
except (Exception, SystemExit) as exc:
|
|
208
192
|
return EvalResult(
|
|
209
193
|
case_id=case_id,
|
|
210
194
|
passed=False,
|
|
211
195
|
score=0.0,
|
|
212
|
-
response=
|
|
196
|
+
response=recorded_response,
|
|
213
197
|
error=f"scoring failed: {str(exc) or exc.__class__.__name__}",
|
|
214
198
|
)
|
|
215
199
|
|
|
@@ -992,4 +976,11 @@ def cmd_env_eval(args) -> int:
|
|
|
992
976
|
)
|
|
993
977
|
|
|
994
978
|
|
|
995
|
-
|
|
979
|
+
# re-exported from eval_args so `flash.cli` keeps importing the eval flag validators from here.
|
|
980
|
+
__all__ = [
|
|
981
|
+
"_MAX_CONCURRENCY",
|
|
982
|
+
"bounded_concurrency",
|
|
983
|
+
"cmd_env_eval",
|
|
984
|
+
"finite_float",
|
|
985
|
+
"positive_int",
|
|
986
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""argparse type validators for `flash env eval`.
|
|
2
|
+
|
|
3
|
+
Separated from `eval.py` so the evaluation driver stays under the file-size limit. These reject a
|
|
4
|
+
bad flag value at parse time, before the command spends anything: a temperature the chat route will
|
|
5
|
+
refuse costs one paid rejection per case if it is discovered case by case instead.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import math
|
|
12
|
+
|
|
13
|
+
# ceiling on parallel model requests: enough to keep a deployment busy without opening so many
|
|
14
|
+
# connections that the suite is rate limited into slower wall-clock than a smaller fan-out.
|
|
15
|
+
_MAX_CONCURRENCY = 32
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def positive_int(value: str) -> int:
|
|
19
|
+
parsed = int(value)
|
|
20
|
+
if parsed < 1:
|
|
21
|
+
raise argparse.ArgumentTypeError("must be at least 1")
|
|
22
|
+
return parsed
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def finite_float(value: str) -> float:
|
|
26
|
+
"""A temperature the chat route will accept.
|
|
27
|
+
|
|
28
|
+
Reject non-finite or negative values before they become one paid rejection per case.
|
|
29
|
+
The nonnegative floor matches `flash/schema/__init__.py`.
|
|
30
|
+
"""
|
|
31
|
+
parsed = float(value)
|
|
32
|
+
if not math.isfinite(parsed):
|
|
33
|
+
raise argparse.ArgumentTypeError(f"must be a finite number, got {value}")
|
|
34
|
+
if parsed < 0.0:
|
|
35
|
+
raise argparse.ArgumentTypeError(f"must be at least 0.0, got {value}")
|
|
36
|
+
return parsed
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def bounded_concurrency(value: str) -> int:
|
|
40
|
+
parsed = positive_int(value)
|
|
41
|
+
if parsed > _MAX_CONCURRENCY:
|
|
42
|
+
raise argparse.ArgumentTypeError(f"must be at most {_MAX_CONCURRENCY}")
|
|
43
|
+
return parsed
|
|
@@ -11,6 +11,8 @@ import tomllib
|
|
|
11
11
|
from collections.abc import Callable
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
|
|
14
|
+
from flash._internal.channel import CLI_NAME
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
def _text(path: Path) -> str:
|
|
16
18
|
"""The file's text, or "" if it cannot be decoded as UTF-8.
|
|
@@ -40,8 +42,15 @@ def _warn_if_retained_starter_files_describe_another_plane(
|
|
|
40
42
|
Deliberately project-INDEPENDENT, unlike `_render_starter`, which interpolates the real uuid: a
|
|
41
43
|
directory scaffolded under one project and rerun under another still holds the OLD uuid, so an
|
|
42
44
|
interpolated marker would miss it. Match the project-invariant prefix instead.
|
|
45
|
+
|
|
46
|
+
CLI-name-independent for the same reason: the guidance names the executable the operator invoked
|
|
47
|
+
(`flash`, `flash-cli`, `python -m flash.cli`), so a scaffold written under the alias carries a
|
|
48
|
+
different command than one written under `flash`. Anchoring on `flash` would silently stop
|
|
49
|
+
recognising those files as hosted scaffolds -- the retained-file warning is the only thing that
|
|
50
|
+
tells the operator their guidance now describes the wrong plane, so it must not depend on which
|
|
51
|
+
entry point happened to write it.
|
|
43
52
|
"""
|
|
44
|
-
push_marker = "
|
|
53
|
+
push_marker = "env push --project "
|
|
45
54
|
# `_render_starter` writes DIFFERENT guidance into each file, so the reverse direction needs
|
|
46
55
|
# both markers: matching only environment.py's would warn about that file while silently
|
|
47
56
|
# keeping a stale evaluations.py beside it.
|
|
@@ -63,11 +72,12 @@ def _warn_if_retained_starter_files_describe_another_plane(
|
|
|
63
72
|
warn(
|
|
64
73
|
f"existing {names} document a self-hosted plane, but this one publishes to the managed "
|
|
65
74
|
"hub; keeping the files unchanged. Their guidance to commit the environment to your own "
|
|
66
|
-
"git repo does not apply here -- run `
|
|
75
|
+
f"git repo does not apply here -- run `{CLI_NAME} env push` and use the returned id "
|
|
76
|
+
"instead"
|
|
67
77
|
)
|
|
68
78
|
return
|
|
69
79
|
warn(
|
|
70
|
-
f"existing {names} still tell you to run `
|
|
80
|
+
f"existing {names} still tell you to run `{CLI_NAME} env push`, which this plane cannot do; "
|
|
71
81
|
"keeping the files unchanged. Commit the environment to a git repo your plane can read and "
|
|
72
82
|
"name it in [environment] id"
|
|
73
83
|
)
|
|
@@ -396,19 +396,23 @@ def _require_setup_project(args) -> str:
|
|
|
396
396
|
# Guidance the starter .py docstrings carry, per plane kind. The templates hold placeholders
|
|
397
397
|
# rather than one plane's wording plus a rewrite pass: matching prose back out after rendering
|
|
398
398
|
# breaks silently the moment a template is reworded.
|
|
399
|
+
# `CLI_NAME`, not a literal `flash`: the executable is `flash-cli` (or `python -m flash.cli`) when
|
|
400
|
+
# `flash` on PATH belongs to RunPod, and the terminal-facing output below already renders it that
|
|
401
|
+
# way. A generated file that says `flash env push` sends the user to the shadowing binary, which
|
|
402
|
+
# exits 0 without publishing anything -- so the instructions look followed and nothing happened.
|
|
399
403
|
_HOSTED_GUIDANCE = {
|
|
400
404
|
"ENVIRONMENT_GUIDANCE": (
|
|
401
405
|
"upload with\n"
|
|
402
|
-
"`
|
|
406
|
+
f"`{CLI_NAME} env push --project PROJECT_UUID --name my-env .`.\n"
|
|
403
407
|
"\n"
|
|
404
408
|
"A managed run should use the returned [environment] id from\n"
|
|
405
|
-
"`
|
|
409
|
+
f"`{CLI_NAME} env push --project PROJECT_UUID --name my-env .`."
|
|
406
410
|
),
|
|
407
411
|
"EVALUATIONS_GUIDANCE": (
|
|
408
412
|
"Publish this file beside environment.py with\n"
|
|
409
|
-
"`
|
|
410
|
-
"model trained on it with `
|
|
411
|
-
"environment, so `env eval` takes no local path."
|
|
413
|
+
f"`{CLI_NAME} env push --project PROJECT_UUID --name my-env .`, then run the suites\n"
|
|
414
|
+
f"against a model trained on it with `{CLI_NAME} env eval TARGET`. The run names the\n"
|
|
415
|
+
"published environment, so `env eval` takes no local path."
|
|
412
416
|
),
|
|
413
417
|
}
|
|
414
418
|
|
|
@@ -91,7 +91,7 @@ from flash.engine.worker.train.rl.config import (
|
|
|
91
91
|
grpo_overrides,
|
|
92
92
|
resolve_grpo_prompts_per_step,
|
|
93
93
|
)
|
|
94
|
-
from flash.envs.adapter import
|
|
94
|
+
from flash.envs.adapter import GitHubTransientError
|
|
95
95
|
from flash.envs.base import load_environment
|
|
96
96
|
from flash.teacher.retry_contract import OPD_RESUME_REVISION_ENV
|
|
97
97
|
|
|
@@ -213,7 +213,10 @@ def require_active_env():
|
|
|
213
213
|
|
|
214
214
|
|
|
215
215
|
def _worker_failure_flags(exc: BaseException) -> dict[str, bool]:
|
|
216
|
-
|
|
216
|
+
# GitHubTransientError covers both the quota case and GitHub being unreachable. The worker's
|
|
217
|
+
# answer to either is the same -- reschedule -- so it catches the base; only the control plane,
|
|
218
|
+
# which has a status code to report, distinguishes them.
|
|
219
|
+
retriable = isinstance(exc, (RetriableInfraError, GitHubTransientError))
|
|
217
220
|
return {"retriable": retriable, "oom": (not retriable and is_cuda_oom(exc))}
|
|
218
221
|
|
|
219
222
|
|
|
@@ -14,7 +14,7 @@ import time
|
|
|
14
14
|
from collections.abc import Callable
|
|
15
15
|
|
|
16
16
|
from flash._internal.diagnostics import sanitize_diagnostic
|
|
17
|
-
from flash.adapters.artifacts import
|
|
17
|
+
from flash.adapters.artifacts import attempt_scoped_artifact_name, has_loadable_adapter_weights
|
|
18
18
|
from flash.engine.profiling.tokenizer import ( # noqa: F401
|
|
19
19
|
load_tokenizer,
|
|
20
20
|
model_revision_kwargs,
|
|
@@ -324,10 +324,20 @@ _CHECKPOINT_TRAINER_STATE = (
|
|
|
324
324
|
|
|
325
325
|
|
|
326
326
|
def _has_deployable_adapter(ckpt_dir: str) -> bool:
|
|
327
|
-
"""Return True if ckpt_dir has a loadable LoRA adapter (config + weights).
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
327
|
+
"""Return True if ckpt_dir has a loadable LoRA adapter (config + weights).
|
|
328
|
+
|
|
329
|
+
Weights via the shared rule rather than the two single-file names, because a save past peft's
|
|
330
|
+
shard size writes ``adapter_model-0000N-of-0000M.<ext>`` plus an index instead. Spelling only the
|
|
331
|
+
single-file names here made this the strict side of a disagreement: serving and export accept the
|
|
332
|
+
sharded save, so a sharded per-step adapter was silently skipped -- or failed a required save --
|
|
333
|
+
for an artifact the rest of the pipeline would have deployed.
|
|
334
|
+
"""
|
|
335
|
+
if not os.path.isfile(os.path.join(ckpt_dir, "adapter_config.json")):
|
|
336
|
+
return False
|
|
337
|
+
try:
|
|
338
|
+
return has_loadable_adapter_weights(os.listdir(ckpt_dir))
|
|
339
|
+
except OSError:
|
|
340
|
+
return False
|
|
331
341
|
|
|
332
342
|
|
|
333
343
|
def _write_deployable_provenance(ckpt_dir: str) -> None:
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""read adapter tensor keys from a downloaded adapter directory, without loading tensor data.
|
|
2
|
+
|
|
3
|
+
helpers must not import ``flash.engine.worker``. heavy dependencies remain lazy so this leaf
|
|
4
|
+
module has no package cycle or eager gpu stack import.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
# A safetensors header is small even for huge models (a few hundred KB at most); 100 MB is a wildly
|
|
10
|
+
# generous ceiling that still refuses a corrupt/hostile file declaring a multi-GB header length
|
|
11
|
+
# before we allocate/read it.
|
|
12
|
+
_MAX_SAFETENSORS_HEADER_BYTES = 100 * 1024 * 1024
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _read_adapter_tensor_keys(adir: str) -> list[str] | None:
|
|
16
|
+
"""return tensor key names from adapter weights without loading tensor data.
|
|
17
|
+
|
|
18
|
+
read only safetensors json headers or torch weights-only state-dict keys. return none if absent.
|
|
19
|
+
|
|
20
|
+
reads whatever peft would bind, which is not always one file: a save past peft's shard size
|
|
21
|
+
writes ``adapter_model-0000N-of-0000M.<ext>`` beside an index, and the keys then live spread
|
|
22
|
+
across the shards. reading only the two single-file names reported such an adapter as having no
|
|
23
|
+
keys at all, so ``_warmstart_adapter_is_loadable`` rejected a warm-start source that serving and
|
|
24
|
+
export both accept.
|
|
25
|
+
"""
|
|
26
|
+
import os
|
|
27
|
+
|
|
28
|
+
from flash.adapters.artifacts import loadable_adapter_weight_files
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
selected = loadable_adapter_weight_files(os.listdir(adir))
|
|
32
|
+
except OSError:
|
|
33
|
+
return None
|
|
34
|
+
if not selected:
|
|
35
|
+
return None
|
|
36
|
+
keys: list[str] = []
|
|
37
|
+
for name in selected:
|
|
38
|
+
path = os.path.join(adir, name)
|
|
39
|
+
if name.endswith(".safetensors"):
|
|
40
|
+
keys.extend(_read_safetensors_tensor_keys(path))
|
|
41
|
+
else:
|
|
42
|
+
keys.extend(_read_bin_tensor_keys(path))
|
|
43
|
+
return keys
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _read_safetensors_tensor_keys(st_path: str) -> list[str]:
|
|
47
|
+
"""the tensor keys declared by one safetensors file's header."""
|
|
48
|
+
import json
|
|
49
|
+
import os
|
|
50
|
+
import struct
|
|
51
|
+
|
|
52
|
+
# safetensors layout: 8-byte LE header length, then the JSON header, then the tensor data.
|
|
53
|
+
# Bound the DECLARED header length against the real file size (and an absolute ceiling)
|
|
54
|
+
# BEFORE reading it, so a corrupt/hostile file can't trigger a huge allocation / long read.
|
|
55
|
+
file_size = os.path.getsize(st_path)
|
|
56
|
+
with open(st_path, "rb") as f:
|
|
57
|
+
len_bytes = f.read(8)
|
|
58
|
+
if len(len_bytes) < 8:
|
|
59
|
+
raise ValueError(f"{st_path}: too small to be a safetensors file")
|
|
60
|
+
(hdr_len,) = struct.unpack("<Q", len_bytes)
|
|
61
|
+
if hdr_len > file_size - 8 or hdr_len > _MAX_SAFETENSORS_HEADER_BYTES:
|
|
62
|
+
raise ValueError(
|
|
63
|
+
f"{st_path}: declared safetensors header length {hdr_len} is implausible "
|
|
64
|
+
f"(file is {file_size} bytes) — refusing to read a corrupt/oversized header"
|
|
65
|
+
)
|
|
66
|
+
header_bytes = f.read(hdr_len)
|
|
67
|
+
if len(header_bytes) < hdr_len:
|
|
68
|
+
raise ValueError(f"{st_path}: truncated safetensors header")
|
|
69
|
+
try:
|
|
70
|
+
header = json.loads(header_bytes)
|
|
71
|
+
except (json.JSONDecodeError, UnicodeDecodeError) as exc:
|
|
72
|
+
# A bare JSONDecodeError ("Expecting value: line 1 column 1") — or a
|
|
73
|
+
# UnicodeDecodeError from non-UTF8 header bytes — gives no clue WHICH adapter is
|
|
74
|
+
# corrupt. Re-raise with the file path so a bad download is diagnosable.
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"{st_path}: safetensors header is not valid JSON "
|
|
77
|
+
f"(corrupt or not a safetensors file): {exc}"
|
|
78
|
+
) from exc
|
|
79
|
+
# The safetensors header MUST be a JSON object keyed by tensor name. A corrupt/hostile file
|
|
80
|
+
# could decode to a list/int/str, which would later blow up with a confusing TypeError
|
|
81
|
+
# downstream (substring search on a non-str). (JSON object keys are always str, so only the
|
|
82
|
+
# container type needs checking.) Reject a non-object header early with a clear message.
|
|
83
|
+
if not isinstance(header, dict):
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"{st_path}: safetensors header is not a JSON object "
|
|
86
|
+
"(corrupt or not a safetensors file)"
|
|
87
|
+
)
|
|
88
|
+
data_size = file_size - 8 - hdr_len
|
|
89
|
+
for key, tensor_info in header.items():
|
|
90
|
+
if key == "__metadata__":
|
|
91
|
+
continue
|
|
92
|
+
offsets = tensor_info.get("data_offsets") if isinstance(tensor_info, dict) else None
|
|
93
|
+
if (
|
|
94
|
+
not isinstance(offsets, list)
|
|
95
|
+
or len(offsets) != 2
|
|
96
|
+
or any(not isinstance(offset, int) or isinstance(offset, bool) for offset in offsets)
|
|
97
|
+
or offsets[0] < 0
|
|
98
|
+
or offsets[0] > offsets[1]
|
|
99
|
+
or offsets[1] > data_size
|
|
100
|
+
):
|
|
101
|
+
raise ValueError(f"{st_path}: invalid or truncated tensor data for {key!r}")
|
|
102
|
+
return [k for k in header if k != "__metadata__"]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _read_bin_tensor_keys(bin_path: str) -> list[str]:
|
|
106
|
+
"""the tensor keys in one torch ``.bin`` adapter state dict, without loading tensor data."""
|
|
107
|
+
import torch
|
|
108
|
+
|
|
109
|
+
state = torch.load(bin_path, map_location="cpu", weights_only=True)
|
|
110
|
+
if not isinstance(state, dict):
|
|
111
|
+
raise ValueError(f"{bin_path}: expected a tensor state dict, got {type(state).__name__}")
|
|
112
|
+
bad = [k for k, v in state.items() if not isinstance(k, str) or not isinstance(v, torch.Tensor)]
|
|
113
|
+
if bad:
|
|
114
|
+
raise ValueError(
|
|
115
|
+
f"{bin_path}: contains non-tensor entries (e.g. {bad[:4]}); "
|
|
116
|
+
"expected a plain PEFT adapter state dict"
|
|
117
|
+
)
|
|
118
|
+
return list(state)
|
|
@@ -448,7 +448,15 @@ def _write_sft_result(options, data, model, child, progress, verified, outputs)
|
|
|
448
448
|
# share of the batch, so a reader reconstructing the token budget off the request would
|
|
449
449
|
# believe each rank held rows it never received.
|
|
450
450
|
"per_device_train_batch_size": child.micro_batch,
|
|
451
|
-
|
|
451
|
+
# over one RANK'S share of the batch, not the global batch. `micro_batch` is already
|
|
452
|
+
# capped to `train_batch_size // world_size` (see `_resolve_sft_width_and_micro_batch`),
|
|
453
|
+
# so dividing the global batch by it was the sequence-parallel formula, where every rank
|
|
454
|
+
# sees the whole batch. under data parallelism it over-counts by the world size, and a
|
|
455
|
+
# reader reconstructing tokens as micro-batch x grad-accum x DP size lands world_size
|
|
456
|
+
# times too high.
|
|
457
|
+
"gradient_accumulation_steps": math.ceil(
|
|
458
|
+
(model.train_batch_size / max(1, child.world_size)) / child.micro_batch
|
|
459
|
+
),
|
|
452
460
|
# verl concatenates either way; the profile's mode records whether more than one
|
|
453
461
|
# example was allowed to share a concatenated batch, which is what a reader of these
|
|
454
462
|
# metrics needs in order to compare a run's step count against its row count.
|