freesolo-flash-dev 1.2.59__tar.gz → 1.2.61__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.2.59 → freesolo_flash_dev-1.2.61}/CHANGELOG.md +4 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/multimodal.py +12 -3
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/core/spec.py +89 -34
- freesolo_flash_dev-1.2.61/flash/core/spec_persistence.py +414 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/backend_common.py +1 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/child/glue.py +58 -3
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/overrides.py +2 -26
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/multiturn.py +26 -7
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/multi_turn.py +83 -12
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/verl_config.py +2 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/capabilities.py +10 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/adapter.py +38 -46
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/__init__.py +11 -2
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/preparation.py +18 -9
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/status.py +11 -3
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/submit.py +40 -18
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/schema/__init__.py +13 -15
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/pyproject.toml +2 -2
- freesolo_flash_dev-1.2.61/tests/test_catalog_only_models.py +88 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_charge_pricing.py +18 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_hardware.py +0 -50
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_managed_config_fields.py +26 -2
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_train.py +4 -22
- freesolo_flash_dev-1.2.61/tests/test_persisted_spec_envelope.py +255 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_rl_train.py +271 -36
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_api.py +5 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_billing.py +3 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_spec_and_validation.py +0 -11
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_spec_contract_bytes.py +105 -3
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verifiers.py +304 -1
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_dryrun.py +16 -12
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/uv.lock +1 -1
- freesolo_flash_dev-1.2.59/flash/core/spec_persistence.py +0 -123
- freesolo_flash_dev-1.2.59/tests/test_catalog_only_models.py +0 -357
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.dockerignore +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.env.example +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/CODEOWNERS +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.gitignore +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/Dockerfile +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/LICENSE +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/NOTICE +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/README.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/SELF_HOSTING.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/deploy/infisical/README.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/deploy/infisical/entrypoint.sh +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/extract_cudart_fix.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/channel.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/fileio.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/logging.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/paths.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/fused_experts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/lora_rank.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/deploy.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/episode.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/eval.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/eval_args.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/imports.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/list.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/push.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/retained.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/setup.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test_evaluations.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test_params.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test_warnings.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/traces.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/train_cost.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/scaffold/TRAINING.md +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/scaffold/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/cost.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/env_panels.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/render.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/tables.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/tty.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/freesolo_api.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/shapes.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/streaming.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/thinking.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/core/catalog.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/kv_sizing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/model_config_probe.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/recipe.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/steps.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/vram.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/reasoning_render.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/tokenizer.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/result/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/result/accounting.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/result/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/opd.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/rl.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/sft.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/hf.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/prefetch.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/wandb_log.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/adapter.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/chatml_mask.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/decoding.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/lora.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/packing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/opd_train.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/opd_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/rl_train.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/rl_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/rng.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/score_batcher.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/sft_train.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/sft_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/client.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/encoding.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/child/runtime.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/step_timing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/finalize.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/batching.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/bridge.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/bridge.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/replay_guard.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/runtime.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/structured.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/failures.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/gkd.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/multiturn_validation.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/prompts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/reporting.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/scoring.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/state.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/validation.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/patches.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/config.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/inputs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/reward_module.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/scoring.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/single_turn.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/config.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/child_io.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/parallelism.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/parent_work.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/cache_security.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/dataset_selection.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/identity.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/namespace_listing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/package/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/package/limits.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/package/unpack.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/auth.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap_console.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap_pip.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/deadline.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/deadline_sleep.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/failmark.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/hostlog.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/http.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/instance.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/poll.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/poll_instance.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/provider.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/terminal_artifacts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/worker.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/hf.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/preload_runpod.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/fit_errors.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/api.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/auth.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/gpus.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/jobs/reap.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/pricing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/job_execution.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/resources.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/serverless/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/serverless/endpoints.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/sharding.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/attempts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/costs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/deadlines.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/reconciliation.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/results/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/results/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/results/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/attach.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/deploy.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/recovery.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/retry_decision.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/seed_submission.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/transitions.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/build.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/manifest.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/profiles.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/adapter_check.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/errors.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/responses.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/streaming.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/thinking.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/billing/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/billing/charges.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/billing/retry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/environment_registry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/envs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/projects.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/reconcile.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/run_registry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/teacher_errors.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/teacher_requests.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/auth.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/db.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/deps.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/internal_client.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/locks.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/runtime.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving_completion.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving_revisions.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving_smoke.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/teacher/limits.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/teacher/retry_contract.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/check_file_size.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/check_function_size.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/check_verl_pin_exists.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/profile.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/teacher.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_sft_thinking_render_live.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_adapter_shard_completeness.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_build_context_contract.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client_import_purity.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_config_env_vars.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_console_upload.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_deploy_alias_move_warning.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_evaluations.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_list_api.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_list_cli.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_list_hub.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_freesolo_api_transport.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_fused_expert_warmstart.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_infisical_secrets.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_multiturn_eos_boundary.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_multiturn_failure_exit.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_replay_guard.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_parasail_teacher.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runtime_capsule.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_startup_block.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_train.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_step_floor.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_step_timing.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_teacher_encoding_contract.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_terminal_artifacts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_type_comment_prose.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verl_checkpoint_export.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verl_child_plugins.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verl_silence_watchdog.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_thinking.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_workflow_contracts.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_zero2_sharding_gate.py +0 -0
|
@@ -21,6 +21,10 @@ This file starts at 1.1.35. Earlier releases are not reconstructed here; use
|
|
|
21
21
|
|
|
22
22
|
### Changed
|
|
23
23
|
|
|
24
|
+
- Multi-turn GRPO now clones each sibling rollout from the task state that produced its prepared
|
|
25
|
+
prompt. Environments that record randomized episode choices on the task during `start_episode`
|
|
26
|
+
are stepped and scored against the same episode the model saw, without sharing mutable state
|
|
27
|
+
between sibling rollouts.
|
|
24
28
|
- A RunPod attempt's stall window is now measured from evidence timestamps rather than from when
|
|
25
29
|
the control plane happened to look at it. The window was seeded from the moment polling started
|
|
26
30
|
and was reset again by the first status read, and a heartbeat was credited at the time it was
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.61
|
|
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
|
|
@@ -250,13 +250,22 @@ def record_has_images(record: dict, messages: list[dict] | None = None) -> bool:
|
|
|
250
250
|
return True
|
|
251
251
|
for message in messages or []:
|
|
252
252
|
content = message.get("content") if isinstance(message, dict) else None
|
|
253
|
-
if
|
|
254
|
-
isinstance(block, dict) and block.get("type") in _IMAGE_BLOCK_TYPES for block in content
|
|
255
|
-
):
|
|
253
|
+
if content_has_images(content):
|
|
256
254
|
return True
|
|
257
255
|
return False
|
|
258
256
|
|
|
259
257
|
|
|
258
|
+
def content_has_images(content: object) -> bool:
|
|
259
|
+
"""Whether one message's ``content`` carries an image block.
|
|
260
|
+
|
|
261
|
+
The single definition of "this message shows the model an image", so a path that cannot carry
|
|
262
|
+
media (the multi-turn GRPO bridge) recognises exactly what the paths that can do.
|
|
263
|
+
"""
|
|
264
|
+
return isinstance(content, list) and any(
|
|
265
|
+
isinstance(block, dict) and block.get("type") in _IMAGE_BLOCK_TYPES for block in content
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
260
269
|
def text_only_prompt_messages(messages: list[dict]) -> list[dict]:
|
|
261
270
|
"""Drop image content blocks while preserving the teacher's message order and text."""
|
|
262
271
|
stripped: list[dict] = []
|
|
@@ -28,6 +28,10 @@ from uuid import UUID
|
|
|
28
28
|
from flash._internal.diagnostics import SECRET_ENV_KEYS_ENV
|
|
29
29
|
from flash.core.catalog import DEFAULT_MODEL, normalize_algorithm
|
|
30
30
|
from flash.core.spec_persistence import (
|
|
31
|
+
DROPPED_TOP_LEVEL_KEYS,
|
|
32
|
+
REMOVED_PERSISTED_TRAIN_KEYS,
|
|
33
|
+
announce_dropped_keys,
|
|
34
|
+
migrated_optimizer_batch,
|
|
31
35
|
opt_float,
|
|
32
36
|
opt_int,
|
|
33
37
|
str_tuple,
|
|
@@ -453,6 +457,58 @@ MANAGED_GPU_KEYS = frozenset(
|
|
|
453
457
|
{"disk_gb", "network_volume", "network_volume_gb", "max_retries", "max_wall_seconds"}
|
|
454
458
|
)
|
|
455
459
|
|
|
460
|
+
# the other two halves of the same boundary. together with the managed gpu registry they name every field
|
|
461
|
+
# that separates the worker contract from the public one -- which is the whole difference between
|
|
462
|
+
# them, and is why `to_dict` can be a projection of `to_internal_dict` rather than a second
|
|
463
|
+
# serializer. they were bare `data.pop(...)` calls, so the boundary existed only as a sequence of
|
|
464
|
+
# statements: nothing could enumerate it, and a field added to one serializer but not the other was
|
|
465
|
+
# invisible until a submit round trip or a recovery digest failed.
|
|
466
|
+
#
|
|
467
|
+
# order is irrelevant (the payload is canonicalized with sort_keys), but presence is a recovery
|
|
468
|
+
# contract: `_preparation_digest` hashes the public payload, so moving a name in or out of this set
|
|
469
|
+
# invalidates the stored digest of every warm-start and workload-profile run in flight.
|
|
470
|
+
#
|
|
471
|
+
# not reused by `_validate_effective_spec`, which keeps its own near-identical list. the difference
|
|
472
|
+
# is one name -- `model_revision` -- and it is deliberate there: the validator excludes it only
|
|
473
|
+
# conditionally, so a historical authored pin stays structurally compared between the two halves.
|
|
474
|
+
# substituting this set would widen that exclusion to every run and drop a real integrity check.
|
|
475
|
+
MANAGED_TOP_LEVEL_KEYS = frozenset(
|
|
476
|
+
{
|
|
477
|
+
# server-assigned identity -- never authored in a config.
|
|
478
|
+
"run_id",
|
|
479
|
+
# runner-managed, and no longer part of the public config or status spec. internal round
|
|
480
|
+
# trips keep the value and marker through to_internal_dict(). historical public specs that
|
|
481
|
+
# emitted these are replayed only while verifying a stored preparation digest, from the
|
|
482
|
+
# exact persisted bytes.
|
|
483
|
+
"model_revision",
|
|
484
|
+
"model_revision_auto",
|
|
485
|
+
# the provenance marker only. gpu.count=1 stays in the public [gpu] object for digest
|
|
486
|
+
# stability; internal round trips carry the marker verbatim.
|
|
487
|
+
"gpu_count_auto",
|
|
488
|
+
"workload_profile",
|
|
489
|
+
"workload_profile_input_digest",
|
|
490
|
+
"workload_profile_producer_version",
|
|
491
|
+
}
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
# platform-managed [train] fields: the control-plane-assigned artifact repo and the resolve-once
|
|
495
|
+
# revision pin of a warm-start source.
|
|
496
|
+
MANAGED_TRAIN_KEYS = frozenset({"hf_repo", "init_from_adapter_revision"})
|
|
497
|
+
|
|
498
|
+
# platform-managed [environment] field: the env ref is resolved once and pinned by the control plane.
|
|
499
|
+
# `pip` deliberately stays public -- it is the author's own scorer dependencies, which only they can
|
|
500
|
+
# declare.
|
|
501
|
+
MANAGED_ENVIRONMENT_KEYS = frozenset({"resolved_sha"})
|
|
502
|
+
|
|
503
|
+
# every managed section, so the public/worker boundary can be walked rather than restated. the two
|
|
504
|
+
# things not here are the ones that are not removals: `train.lora_rank`/`lora_alpha` are stripped
|
|
505
|
+
# only for a warm start, and `gpu.type_fallbacks` is respelled into `gpu.type` rather than dropped.
|
|
506
|
+
MANAGED_SECTION_KEYS = (
|
|
507
|
+
("train", MANAGED_TRAIN_KEYS),
|
|
508
|
+
("gpu", MANAGED_GPU_KEYS),
|
|
509
|
+
("environment", MANAGED_ENVIRONMENT_KEYS),
|
|
510
|
+
)
|
|
511
|
+
|
|
456
512
|
|
|
457
513
|
@dataclass(frozen=True)
|
|
458
514
|
class WandbSpec:
|
|
@@ -555,52 +611,44 @@ class JobSpec:
|
|
|
555
611
|
parser would reject, so the result re-validates through ``flash.schema.spec_from_dict``. Do
|
|
556
612
|
not hand its output to a worker or provider path -- those need ``to_internal_dict()``.
|
|
557
613
|
|
|
614
|
+
Built as a PROJECTION of the worker payload, because that is the actual relationship: the
|
|
615
|
+
public contract is the worker contract minus the platform-managed fields, which
|
|
616
|
+
MANAGED_TOP_LEVEL_KEYS and MANAGED_SECTION_KEYS name. This is still a blacklist -- a newly
|
|
617
|
+
added field is public until something strips it, exactly as before -- but the strips are now
|
|
618
|
+
enumerable rather than a run of statements, so a test can assert the boundary instead of
|
|
619
|
+
trusting that two independent `asdict(self)` bodies were kept in sync by hand. What the
|
|
620
|
+
registries deliberately do NOT cover is the two adjustments below that are not removals.
|
|
621
|
+
|
|
558
622
|
Its bytes are a recovery contract. ``_preparation_digest`` hashes this output as canonical
|
|
559
623
|
JSON, so key PRESENCE is load-bearing even though key order is not: adding or dropping one
|
|
560
624
|
key here invalidates the stored digest of every warm-start and workload-profile run in
|
|
561
625
|
flight, which fails integrity validation on recovery.
|
|
562
626
|
"""
|
|
563
|
-
data =
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
# digest, using the exact value from the persisted bytes.
|
|
570
|
-
data.pop("model_revision", None)
|
|
571
|
-
data.pop("model_revision_auto", None)
|
|
572
|
-
# keep gpu.count=1 in the public gpu object for preparation-digest stability. only the
|
|
573
|
-
# platform-managed provenance marker is stripped; internal round trips carry it verbatim.
|
|
574
|
-
data.pop("gpu_count_auto", None)
|
|
575
|
-
data.pop("workload_profile_input_digest", None)
|
|
576
|
-
data.pop("workload_profile_producer_version", None)
|
|
577
|
-
data.pop("workload_profile", None)
|
|
627
|
+
data = self.to_internal_dict()
|
|
628
|
+
for managed in MANAGED_TOP_LEVEL_KEYS:
|
|
629
|
+
data.pop(managed, None)
|
|
630
|
+
for section, managed_keys in MANAGED_SECTION_KEYS:
|
|
631
|
+
for managed in managed_keys:
|
|
632
|
+
data[section].pop(managed, None)
|
|
578
633
|
train = data["train"]
|
|
579
|
-
train.pop("init_from_adapter_revision", None)
|
|
580
|
-
train.pop("hf_repo", None) # control-plane-assigned artifact repo
|
|
581
634
|
if train.get("init_from_adapter"):
|
|
582
635
|
# the source adapter's topology is authoritative for a warm start, so the parser rejects
|
|
583
636
|
# both keys alongside init_from_adapter. the runner writes the inherited rank/alpha onto
|
|
584
637
|
# the public spec, so they must be stripped here or the submit round trip re-validates
|
|
585
|
-
# a combination the parser refuses.
|
|
638
|
+
# a combination the parser refuses. conditional, so it cannot be a registry entry.
|
|
586
639
|
train.pop("lora_rank", None)
|
|
587
640
|
train.pop("lora_alpha", None)
|
|
588
|
-
#
|
|
641
|
+
# restore the public list spelling for an ordered pin -- a reshape rather than a removal,
|
|
642
|
+
# which is the other thing no registry can express. the default stands in for the key the
|
|
643
|
+
# worker payload omits when there are no fallbacks: unlike `providers`, this one is read
|
|
644
|
+
# back, so it cannot rely on the omission alone.
|
|
589
645
|
gpu = data["gpu"]
|
|
590
|
-
for managed in MANAGED_GPU_KEYS:
|
|
591
|
-
gpu.pop(managed, None)
|
|
592
|
-
# restore the public list spelling for an ordered pin.
|
|
593
646
|
fallbacks = gpu.pop("type_fallbacks", ())
|
|
594
647
|
if fallbacks:
|
|
595
648
|
gpu["type"] = [gpu["type"], *fallbacks]
|
|
596
|
-
#
|
|
597
|
-
# the
|
|
598
|
-
|
|
599
|
-
gpu.pop("providers", None)
|
|
600
|
-
data["environment"].pop("resolved_sha", None) # resolve-once env ref pin
|
|
601
|
-
# [environment] pip stays in the payload: it is the author's own scorer dependencies, which
|
|
602
|
-
# only they can declare. The submit paths append it to worker_pip_for_env, so what travels
|
|
603
|
-
# here is the extra requirements, not the worker's own.
|
|
649
|
+
# an empty `providers` needs no strip: the worker payload this projects from already omits
|
|
650
|
+
# it, for the same reason the public contract wants it gone -- an internal default must not
|
|
651
|
+
# read back as an authored empty list, which the parser rejects as a likely config bug.
|
|
604
652
|
return data
|
|
605
653
|
|
|
606
654
|
def to_internal_dict(self) -> dict[str, Any]:
|
|
@@ -642,9 +690,10 @@ class JobSpec:
|
|
|
642
690
|
if not isinstance(data, dict):
|
|
643
691
|
raise TypeError("job spec must be an object")
|
|
644
692
|
allowed_top_level = {item.name for item in fields(cls)}
|
|
645
|
-
unknown_top_level = sorted(set(data) - allowed_top_level)
|
|
693
|
+
unknown_top_level = sorted(set(data) - allowed_top_level - DROPPED_TOP_LEVEL_KEYS)
|
|
646
694
|
if unknown_top_level:
|
|
647
695
|
raise ValueError(f"job spec has unknown key(s): {', '.join(unknown_top_level)}")
|
|
696
|
+
announce_dropped_keys(data)
|
|
648
697
|
env = data.get("environment") or {}
|
|
649
698
|
# Reject stale payloads carrying a local `path`; worker only runs published env ids.
|
|
650
699
|
if isinstance(env, dict) and env.get("path"):
|
|
@@ -652,7 +701,12 @@ class JobSpec:
|
|
|
652
701
|
"local environment paths are no longer supported; the worker only runs "
|
|
653
702
|
"published Freesolo environment ids"
|
|
654
703
|
)
|
|
655
|
-
train = validated_section(
|
|
704
|
+
train = validated_section(
|
|
705
|
+
data,
|
|
706
|
+
"train",
|
|
707
|
+
{item.name for item in fields(TrainSpec)},
|
|
708
|
+
removed=REMOVED_PERSISTED_TRAIN_KEYS,
|
|
709
|
+
)
|
|
656
710
|
gpu = validated_section(data, "gpu", {item.name for item in fields(GpuSpec)})
|
|
657
711
|
gpu_type, gpu_type_fallbacks = _parse_persisted_gpu_types(gpu)
|
|
658
712
|
provider, providers = validated_persisted_providers(gpu, gpu_type, gpu_type_fallbacks)
|
|
@@ -661,8 +715,9 @@ class JobSpec:
|
|
|
661
715
|
raise TypeError("project must be a string")
|
|
662
716
|
project = require_project_id(project_raw) if project_raw.strip() else ""
|
|
663
717
|
algorithm = normalize_algorithm(data.get("algorithm", cls.algorithm))
|
|
664
|
-
|
|
665
|
-
|
|
718
|
+
# one reading of the optimizer batch for both keys: the rollout spelling changed in 1.1.43
|
|
719
|
+
# and a persisted spec can still carry the old one.
|
|
720
|
+
batch_size, prompts_per_step = migrated_optimizer_batch(train, algorithm)
|
|
666
721
|
return cls(
|
|
667
722
|
model=data.get("model", cls.model),
|
|
668
723
|
model_revision=_model_revision(data.get("model_revision", cls.model_revision)),
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""Decoding rules for PERSISTED job-spec records, as distinct from authored configuration.
|
|
2
|
+
|
|
3
|
+
`JobSpec` serves four different contracts, and this module owns exactly one of them: reading back
|
|
4
|
+
bytes that were already written to `~/.flash/runs/<run_id>.json`. That is not the same job as
|
|
5
|
+
validating a config a user just wrote, and the two must not be confused:
|
|
6
|
+
|
|
7
|
+
- authored configuration is parsed by `flash.schema.spec_from_dict`, which is STRICT. an unknown key
|
|
8
|
+
is a typo in a file the author can still fix, so it fails loudly.
|
|
9
|
+
- a persisted record is parsed by `JobSpec.from_dict`, which is TOLERANT by necessity. the record is
|
|
10
|
+
immutable history: it was written by an older Flash, it is never rewritten, and a run that is
|
|
11
|
+
still training depends on it decoding. rejecting it strands the run.
|
|
12
|
+
|
|
13
|
+
So the coercions here are deliberately looser than anything the authored parser would accept, and
|
|
14
|
+
the migrations exist to keep specific historical spellings readable. Neither belongs on the
|
|
15
|
+
submission path.
|
|
16
|
+
|
|
17
|
+
Serialized-byte warning: `flash/runner/preparation.py::_preparation_digest` sha256-hashes the
|
|
18
|
+
canonical JSON of `to_dict()` and `to_internal_dict()` output. Key ORDER is safe there
|
|
19
|
+
(`sort_keys=True`), but key PRESENCE is not -- adding, dropping, or renaming a key in a decode path
|
|
20
|
+
changes the digest and fails integrity validation for every warm-start and workload-profile run in
|
|
21
|
+
flight. Change decoding here only with the corpus gate green.
|
|
22
|
+
|
|
23
|
+
These functions take plain dicts and return plain dicts and scalars. That is the rule that keeps the
|
|
24
|
+
module importable by `spec.py` rather than the other way round, and it is why `validated_section`
|
|
25
|
+
takes its allowed-key set as an argument instead of reading `fields(TrainSpec)` itself.
|
|
26
|
+
|
|
27
|
+
What is deliberately NOT here: `_coerce_wandb` and `_parse_persisted_gpu_types` are also called only
|
|
28
|
+
from `JobSpec.from_dict`, so they belong to this contract by usage -- but they construct `WandbSpec`
|
|
29
|
+
and reach `_validated_gpu_type`, which `__post_init__` needs too. Moving them would make this module
|
|
30
|
+
import the dataclasses that import it. The boundary is therefore "persisted-record logic that does
|
|
31
|
+
not depend on the spec types themselves"; `VersionedPersistedSpecEnvelope` follows that rule too.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import logging
|
|
37
|
+
from collections.abc import Mapping
|
|
38
|
+
from dataclasses import dataclass, field
|
|
39
|
+
from typing import Any, ClassVar
|
|
40
|
+
|
|
41
|
+
from flash.core.catalog import normalize_algorithm, samples_on_policy
|
|
42
|
+
|
|
43
|
+
# removed public top-level fields that a persisted record can still carry. stored run records are
|
|
44
|
+
# never rewritten, and effective_preparation.worker_spec is written with to_internal_dict() (asdict),
|
|
45
|
+
# which emitted every field including the defaulted ones -- so every record written before a field
|
|
46
|
+
# was dropped still names it. this registry also drives historical public-digest replay for
|
|
47
|
+
# model_revision, which remains an internal field. without it a still-running job can lose its
|
|
48
|
+
# recovery, deploy, and serving paths after the upgrade.
|
|
49
|
+
#
|
|
50
|
+
# ignored on read only. most keys here no longer exist as jobspec fields; model_revision remains an
|
|
51
|
+
# internal runner field, but the public schema rejects it and to_dict omits it. keeping it in this set
|
|
52
|
+
# lets digest recovery identify the historical public key without weakening jobspec.from_dict.
|
|
53
|
+
DROPPED_TOP_LEVEL_KEYS = frozenset(
|
|
54
|
+
{"model_policy", "model_revision", "worker_env", "workload_profile_kind"}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# tolerating a dropped key keeps a pre-upgrade run's recovery path, but the values behind it stop
|
|
58
|
+
# being applied -- so a run that authored them now trains on managed defaults instead of what was
|
|
59
|
+
# submitted. that is announced rather than silent. only user-authorable keys qualify: model_policy
|
|
60
|
+
# was platform-managed (to_dict popped it), so its loss cannot change what a submitted config asked
|
|
61
|
+
# for. the values are deliberately not forwarded -- doing so would reinstate the override table this
|
|
62
|
+
# removal exists to close, and would deliver it without the validation the deleted parser performed.
|
|
63
|
+
_ANNOUNCED_DROPPED_KEYS = frozenset({"worker_env"})
|
|
64
|
+
|
|
65
|
+
# removed [train] keys a persisted record can still carry. deliberately narrow: a key is listed only
|
|
66
|
+
# once its behavior is gone, so an unlisted unknown key stays fatal rather than silently ignored.
|
|
67
|
+
REMOVED_PERSISTED_TRAIN_KEYS = frozenset({"advantage_clip"})
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def announce_dropped_keys(data: dict[str, Any]) -> None:
|
|
71
|
+
"""Log the removed user-authored keys a persisted record still carries and no longer applies.
|
|
72
|
+
|
|
73
|
+
Only announced when the payload names the run. A public spec is ``to_dict()`` output, which pops
|
|
74
|
+
the server-assigned run_id, and the same stored run is read through both shapes -- so warning
|
|
75
|
+
without an id would emit an unactionable "run <unknown>" line and duplicate the identified one
|
|
76
|
+
the worker-spec read already produced. Every provisioned run records an internal worker spec
|
|
77
|
+
(asdict, run_id included), and that is the read this fires on.
|
|
78
|
+
"""
|
|
79
|
+
run_id = str(data.get("run_id") or "").strip()
|
|
80
|
+
if not run_id:
|
|
81
|
+
return
|
|
82
|
+
for key in sorted(_ANNOUNCED_DROPPED_KEYS):
|
|
83
|
+
value = data.get(key)
|
|
84
|
+
if not value:
|
|
85
|
+
continue
|
|
86
|
+
names = ", ".join(sorted(str(k) for k in value)) if isinstance(value, dict) else str(value)
|
|
87
|
+
logging.getLogger("flash.spec").warning(
|
|
88
|
+
"run %s was submitted with [%s] (%s); that table was removed and its values are NOT "
|
|
89
|
+
"applied -- this run uses managed defaults instead. resubmit without it if the run "
|
|
90
|
+
"depends on those values.",
|
|
91
|
+
run_id,
|
|
92
|
+
key,
|
|
93
|
+
names,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def validated_section(
|
|
98
|
+
data: dict[str, Any],
|
|
99
|
+
name: str,
|
|
100
|
+
allowed: set[str],
|
|
101
|
+
*,
|
|
102
|
+
removed: frozenset[str] = frozenset(),
|
|
103
|
+
) -> dict[str, Any]:
|
|
104
|
+
"""Read one nested block (``[train]``, ``[gpu]``) of a persisted record, rejecting unknown keys.
|
|
105
|
+
|
|
106
|
+
A missing block and an explicit null are the same state -- both mean "authored nothing" -- so both
|
|
107
|
+
normalize to empty rather than one of them raising. ``removed`` names keys whose behavior is gone:
|
|
108
|
+
they are dropped silently, because the record is immutable history and cannot be rewritten. An
|
|
109
|
+
unlisted unknown key stays fatal, which is what keeps the tolerance narrow instead of turning
|
|
110
|
+
every typo in a stored record into a silent default.
|
|
111
|
+
"""
|
|
112
|
+
section = data.get(name)
|
|
113
|
+
if section is None:
|
|
114
|
+
section = {}
|
|
115
|
+
if not isinstance(section, dict):
|
|
116
|
+
raise TypeError(f"{name} must be an object")
|
|
117
|
+
section = {key: value for key, value in section.items() if key not in removed}
|
|
118
|
+
unknown = sorted(set(section) - allowed)
|
|
119
|
+
if unknown:
|
|
120
|
+
raise ValueError(f"{name} has unknown key(s): {', '.join(unknown)}")
|
|
121
|
+
return section
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def validated_persisted_providers(
|
|
125
|
+
gpu: dict[str, Any], gpu_type: str, gpu_type_fallbacks: tuple[str, ...]
|
|
126
|
+
) -> tuple[str, tuple[str, ...]]:
|
|
127
|
+
"""``(provider, providers)`` from a persisted ``[gpu]`` block, cross-checked against its classes.
|
|
128
|
+
|
|
129
|
+
``GpuSpec.__post_init__`` runs the same both-set check but cannot replace this one: ``allow_empty``
|
|
130
|
+
here keys off whether the record CARRIED a ``providers`` key, and that presence is exactly what the
|
|
131
|
+
dataclass has already lost by the time it validates. An explicitly empty preference and an absent
|
|
132
|
+
one are different states in a stored record.
|
|
133
|
+
"""
|
|
134
|
+
from flash.providers import PROVIDER_NAMES, validated_provider_preferences
|
|
135
|
+
|
|
136
|
+
provider = gpu.get("provider", "")
|
|
137
|
+
if not isinstance(provider, str):
|
|
138
|
+
raise TypeError("gpu.provider must be a string")
|
|
139
|
+
provider = provider.strip().lower()
|
|
140
|
+
providers = validated_provider_preferences(
|
|
141
|
+
gpu.get("providers", ()), allow_empty="providers" not in gpu
|
|
142
|
+
)
|
|
143
|
+
if provider and providers:
|
|
144
|
+
raise ValueError("gpu.provider and gpu.providers cannot both be set")
|
|
145
|
+
if provider or providers or gpu_type:
|
|
146
|
+
from flash.providers.base import providers_for
|
|
147
|
+
|
|
148
|
+
if provider and provider not in PROVIDER_NAMES:
|
|
149
|
+
raise ValueError(f"unknown gpu.provider {provider!r}")
|
|
150
|
+
# a hard provider pin must carry every acceptable class. provider preferences stay soft: an
|
|
151
|
+
# ineligible named provider contributes no candidate, while eligible named or unnamed
|
|
152
|
+
# configured providers remain available for failover.
|
|
153
|
+
for candidate in (gpu_type, *gpu_type_fallbacks):
|
|
154
|
+
if candidate and provider and provider not in providers_for(candidate):
|
|
155
|
+
raise ValueError(
|
|
156
|
+
f"gpu.provider {provider!r} cannot provision gpu.type {candidate!r}"
|
|
157
|
+
)
|
|
158
|
+
return provider, providers
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def str_tuple(value: Any) -> tuple[str, ...]:
|
|
162
|
+
"""Normalize a string-or-list knob to a tuple of strings; a bare string is one element, not iterated."""
|
|
163
|
+
if value is None:
|
|
164
|
+
return ()
|
|
165
|
+
if isinstance(value, str):
|
|
166
|
+
return (value,) if value else ()
|
|
167
|
+
return tuple(s for s in (str(x) for x in value) if s)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def volume_gb(value: Any, default: int = 100) -> int:
|
|
171
|
+
"""Parse volume size in GB; non-positive / non-numeric / missing values return default."""
|
|
172
|
+
if isinstance(value, bool):
|
|
173
|
+
# bool is an int subclass; reject to avoid int(True)==1 becoming a 1 GB volume.
|
|
174
|
+
return default
|
|
175
|
+
try:
|
|
176
|
+
gb = int(value)
|
|
177
|
+
except (TypeError, ValueError):
|
|
178
|
+
return default
|
|
179
|
+
return gb if gb > 0 else default
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def opt_int(value: Any) -> int | None:
|
|
183
|
+
"""Parse optional int; rejects bools (bool is int subclass — int(True)==1 is a footgun)."""
|
|
184
|
+
if value is None:
|
|
185
|
+
return None
|
|
186
|
+
if isinstance(value, bool):
|
|
187
|
+
raise TypeError(f"expected a number, got bool {value!r}")
|
|
188
|
+
return int(value)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def opt_float(value: Any) -> float | None:
|
|
192
|
+
"""Parse optional float; rejects bools (mirrors ``opt_int``)."""
|
|
193
|
+
if value is None:
|
|
194
|
+
return None
|
|
195
|
+
if isinstance(value, bool):
|
|
196
|
+
raise TypeError(f"expected a number, got bool {value!r}")
|
|
197
|
+
return float(value)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def migrated_optimizer_batch(train: dict, algorithm: str) -> tuple[int | None, int | None]:
|
|
201
|
+
"""``(batch_size, prompts_per_step)`` with the pre-1.1.43 rollout spelling migrated.
|
|
202
|
+
|
|
203
|
+
grpo/opd authored the optimizer batch as ``batch_size`` until it was split into
|
|
204
|
+
``prompts_per_step``. The schema rejects the old name on SUBMISSION, but `from_dict` also
|
|
205
|
+
reparses PERSISTED specs, and the deployed release (1.1.40) has no ``prompts_per_step`` at all
|
|
206
|
+
-- so every rollout run in flight across this upgrade carries only the old key. The workers read
|
|
207
|
+
``prompts_per_step`` alone, so without this a recovered run silently resumes on the recipe
|
|
208
|
+
default: 64 instead of an authored 32 on grpo, which OOMs a card rented for 32, and 8 on opd.
|
|
209
|
+
|
|
210
|
+
The old key is MOVED, not copied, and is dropped whenever the new one is present. Leaving it
|
|
211
|
+
populated would re-emit both names from ``to_dict()``, and a spec carrying both is rejected by
|
|
212
|
+
the schema -- breaking the resubmit that recovery and ``flash runs get`` perform, and leaving
|
|
213
|
+
`vram.py::_optimizer_batch_value` (which takes the larger of the two) free to size a card off
|
|
214
|
+
the stale value that ranking ignores. That applies to a payload written mid-upgrade carrying
|
|
215
|
+
BOTH spellings too: ``prompts_per_step`` wins, so the superseded key has to go with it.
|
|
216
|
+
|
|
217
|
+
A non-positive legacy value is discarded rather than migrated: ``minimum=1`` would have
|
|
218
|
+
rejected it at submission, and carrying it forward only fails later on a rented GPU. It is
|
|
219
|
+
discarded from BOTH names for the same round-trip reason -- retaining it under the old one
|
|
220
|
+
would re-emit a key the schema rejects for this algorithm.
|
|
221
|
+
"""
|
|
222
|
+
batch_size = opt_int(train.get("batch_size"))
|
|
223
|
+
prompts_per_step = opt_int(train.get("prompts_per_step"))
|
|
224
|
+
if not samples_on_policy(algorithm):
|
|
225
|
+
return batch_size, prompts_per_step
|
|
226
|
+
if prompts_per_step is not None:
|
|
227
|
+
return None, prompts_per_step
|
|
228
|
+
return None, batch_size if batch_size is not None and batch_size >= 1 else None
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
_PREPARATION_ENVELOPE_VERSION = 1
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _prepared_before_public_alpha(raw_public: object) -> bool:
|
|
235
|
+
"""True when this run's PERSISTED public spec predates ``lora_alpha`` becoming authorable.
|
|
236
|
+
|
|
237
|
+
The discriminator is the stored bytes, not this build's serialization: a snapshot prepared
|
|
238
|
+
before the change hashed a public spec with no alpha key, and its digest can only be reproduced
|
|
239
|
+
the same way. status.spec is never rewritten, so this answer is stable for the run's life.
|
|
240
|
+
|
|
241
|
+
A warm-start spec is excluded even though it also omits alpha -- to_dict() strips rank and alpha
|
|
242
|
+
for those in every version, so absence there says nothing about when the run was prepared, and
|
|
243
|
+
treating it as legacy would drop a binding that costs nothing to keep.
|
|
244
|
+
"""
|
|
245
|
+
if not isinstance(raw_public, dict):
|
|
246
|
+
return False
|
|
247
|
+
train = raw_public.get("train")
|
|
248
|
+
if not isinstance(train, dict) or "lora_alpha" in train:
|
|
249
|
+
return False
|
|
250
|
+
return not train.get("init_from_adapter")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
_ROLLOUT_BATCH_KEYS = ("batch_size", "prompts_per_step")
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _stored_rollout_batch_spelling(raw_spec: object) -> dict[str, Any] | None:
|
|
257
|
+
"""How a PERSISTED rollout spec spelled its optimizer batch, or None if it is not one.
|
|
258
|
+
|
|
259
|
+
Same discriminator style as ``_prepared_before_public_alpha``: the answer comes from the stored
|
|
260
|
+
bytes, which are never rewritten, so it is stable for the run's life.
|
|
261
|
+
|
|
262
|
+
``JobSpec.from_dict`` MOVES the pre-1.1.43 ``batch_size`` onto ``prompts_per_step`` when
|
|
263
|
+
reparsing, so rehashing a persisted spec with today's parse can produce different bytes than
|
|
264
|
+
were hashed at persist time -- failing integrity validation for exactly the warm-start grpo/opd
|
|
265
|
+
runs this migration exists to rescue.
|
|
266
|
+
|
|
267
|
+
Both keys are reported, rather than just the value there is to migrate. Reporting only the
|
|
268
|
+
latter conflates snapshots that have nothing to move but still change shape: a mixed-version
|
|
269
|
+
payload storing both names (the migration drops the old one, so the stored ``batch_size`` still
|
|
270
|
+
has to be rehashed), one whose legacy value is non-positive (discarded by the parser), and a
|
|
271
|
+
modern payload (nothing to do). Replaying the stored spelling covers all of them uniformly.
|
|
272
|
+
|
|
273
|
+
A key merely holding null reports None; a key genuinely OMITTED is omitted from the reading too,
|
|
274
|
+
because the two hash differently. Every digest is taken over a serialized ``JobSpec``, which
|
|
275
|
+
emits both names, so a null was really hashed as null -- while 1.1.40 predates
|
|
276
|
+
``prompts_per_step`` entirely and hashed no such key. Each half's reading therefore carries its
|
|
277
|
+
OWN absence rather than sharing one flag: after a re-persist the worker half is rewritten in the
|
|
278
|
+
modern shape while ``status.spec`` keeps the legacy one, so the halves genuinely disagree about
|
|
279
|
+
which keys exist and a single flag would misdescribe one of them.
|
|
280
|
+
|
|
281
|
+
This is not a way to forge a batch: the replayed values are the STORED ones, and the digest they
|
|
282
|
+
are compared against was computed over the ORIGINAL ones, so any tampering still mismatches.
|
|
283
|
+
|
|
284
|
+
Only a rollout algorithm is eligible: for sft ``batch_size`` is the current, un-migrated name,
|
|
285
|
+
which ``from_dict`` leaves alone.
|
|
286
|
+
"""
|
|
287
|
+
if not isinstance(raw_spec, dict):
|
|
288
|
+
return None
|
|
289
|
+
if not samples_on_policy(normalize_algorithm(str(raw_spec.get("algorithm") or ""))):
|
|
290
|
+
return None
|
|
291
|
+
train = raw_spec.get("train")
|
|
292
|
+
if not isinstance(train, dict):
|
|
293
|
+
return None
|
|
294
|
+
stored = {key: train.get(key) for key in _ROLLOUT_BATCH_KEYS}
|
|
295
|
+
# the 1.1.40 shape, read off the bytes themselves: it carried the old name and no new one.
|
|
296
|
+
# a payload omitting both says nothing about when it was written, and the serializer always
|
|
297
|
+
# emits both -- so treating that as absence would drop a key that was hashed.
|
|
298
|
+
if "batch_size" in train and "prompts_per_step" not in train:
|
|
299
|
+
del stored["prompts_per_step"]
|
|
300
|
+
return stored
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _restore_rollout_batch_spelling(payload: dict, stored: dict | None) -> None:
|
|
304
|
+
"""Put the optimizer-batch keys back exactly as the stored payload hashed them.
|
|
305
|
+
|
|
306
|
+
A key absent from ``stored`` was absent from the hashed bytes, so it is removed rather than
|
|
307
|
+
written -- that is the 1.1.40 shape, which predates ``prompts_per_step``.
|
|
308
|
+
"""
|
|
309
|
+
if stored is None:
|
|
310
|
+
return
|
|
311
|
+
train = payload.get("train")
|
|
312
|
+
if not isinstance(train, dict):
|
|
313
|
+
return
|
|
314
|
+
for key in _ROLLOUT_BATCH_KEYS:
|
|
315
|
+
if key in stored:
|
|
316
|
+
train[key] = stored[key]
|
|
317
|
+
else:
|
|
318
|
+
train.pop(key, None)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
@dataclass(frozen=True)
|
|
322
|
+
class VersionedPersistedSpecEnvelope:
|
|
323
|
+
"""How a persisted snapshot's bytes were spelled when its digest was taken.
|
|
324
|
+
|
|
325
|
+
Every field here answers one question -- what did the STORED payload look like, not what does
|
|
326
|
+
this build serialize -- and each is read off bytes that are never rewritten, so the answers are
|
|
327
|
+
stable for the run's life. They were previously five keyword arguments threaded through three
|
|
328
|
+
call sites in lockstep; nothing ever passed a meaningful subset, because they are one reading.
|
|
329
|
+
|
|
330
|
+
Empty is the correct default for a snapshot written by this build: there is nothing to rewind,
|
|
331
|
+
so ``rewind()`` is a no-op and the digest is taken over today's serialization directly.
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
CURRENT_VERSION: ClassVar[int] = _PREPARATION_ENVELOPE_VERSION
|
|
335
|
+
|
|
336
|
+
version: int = CURRENT_VERSION
|
|
337
|
+
worker_dropped_keys: Mapping[str, Any] = field(default_factory=dict)
|
|
338
|
+
public_dropped_keys: Mapping[str, Any] = field(default_factory=dict)
|
|
339
|
+
public_omits_lora_alpha: bool = False
|
|
340
|
+
worker_rollout_batch: dict[str, Any] | None = None
|
|
341
|
+
public_rollout_batch: dict[str, Any] | None = None
|
|
342
|
+
|
|
343
|
+
@classmethod
|
|
344
|
+
def read(
|
|
345
|
+
cls,
|
|
346
|
+
snapshot: object,
|
|
347
|
+
raw_public: object,
|
|
348
|
+
*,
|
|
349
|
+
include_worker: bool = True,
|
|
350
|
+
) -> VersionedPersistedSpecEnvelope:
|
|
351
|
+
"""Read one persisted preparation envelope and its public half.
|
|
352
|
+
|
|
353
|
+
Historical snapshots predate the explicit version key and are version 1 by definition. A
|
|
354
|
+
newer version is rejected rather than guessed: the digest cannot reveal which serialization
|
|
355
|
+
produced it, so an older build has no safe replay strategy for bytes it does not understand.
|
|
356
|
+
|
|
357
|
+
The public and worker halves keep independent spelling. After re-persistence the worker half
|
|
358
|
+
is rewritten in the modern shape while ``status.spec`` stays historical; ``include_worker``
|
|
359
|
+
is false on that write path so old worker spelling is not replayed onto newly serialized bytes.
|
|
360
|
+
"""
|
|
361
|
+
snapshot = snapshot if isinstance(snapshot, Mapping) else {}
|
|
362
|
+
version = snapshot.get("version", cls.CURRENT_VERSION)
|
|
363
|
+
if isinstance(version, bool) or not isinstance(version, int) or version < 1:
|
|
364
|
+
raise ValueError("persisted preparation envelope version must be a positive integer")
|
|
365
|
+
if version != cls.CURRENT_VERSION:
|
|
366
|
+
raise ValueError(f"unsupported persisted preparation envelope version {version}")
|
|
367
|
+
raw_worker = snapshot.get("worker_spec") if include_worker else None
|
|
368
|
+
return cls(
|
|
369
|
+
version=version,
|
|
370
|
+
worker_dropped_keys=_dropped_key_subset(raw_worker),
|
|
371
|
+
public_dropped_keys=_dropped_key_subset(raw_public),
|
|
372
|
+
public_omits_lora_alpha=_prepared_before_public_alpha(raw_public),
|
|
373
|
+
worker_rollout_batch=_stored_rollout_batch_spelling(raw_worker),
|
|
374
|
+
public_rollout_batch=_stored_rollout_batch_spelling(raw_public),
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
def rewind(self, public_payload: dict, worker_payload: dict) -> None:
|
|
378
|
+
"""Rewind today's serialization to the bytes this snapshot actually hashed.
|
|
379
|
+
|
|
380
|
+
None of this can forge a value: every replayed key comes from the STORED payload, and the
|
|
381
|
+
digest it is compared against was computed over the ORIGINAL one, so tampering still
|
|
382
|
+
mismatches. Only keys registered as historical removals are honoured -- filtered HERE and
|
|
383
|
+
not just at ``read()``, because an instance can be built directly -- so a field the
|
|
384
|
+
dataclass still defines always comes from the spec itself.
|
|
385
|
+
"""
|
|
386
|
+
# the rollout optimizer batch was renamed `batch_size` -> `prompts_per_step`, and from_dict
|
|
387
|
+
# moves it when reparsing -- so a spec written before or across the rename only reproduces
|
|
388
|
+
# its digest under the spelling it actually stored, including a key it did not have.
|
|
389
|
+
_restore_rollout_batch_spelling(worker_payload, self.worker_rollout_batch)
|
|
390
|
+
_restore_rollout_batch_spelling(public_payload, self.public_rollout_batch)
|
|
391
|
+
# a pre-upgrade snapshot hashed `model_policy` in (to_internal_dict was asdict, so it emitted
|
|
392
|
+
# the defaulted value) and the field no longer exists, so rehashing without it fails a
|
|
393
|
+
# still-valid run's integrity check on recovery.
|
|
394
|
+
worker_payload.update(_dropped_key_subset(self.worker_dropped_keys))
|
|
395
|
+
# a dropped key that was user-authorable was hashed on the public side too. model_policy
|
|
396
|
+
# never was, so the worker half sufficed for it; model_revision and worker_env were.
|
|
397
|
+
public_payload.update(_dropped_key_subset(self.public_dropped_keys))
|
|
398
|
+
# ``lora_alpha`` became user-authorable, so to_dict() now emits it for non-warm-start runs.
|
|
399
|
+
# scoped to legacy snapshots only: a digest created from here on binds the public alpha, and
|
|
400
|
+
# without that binding the two halves can disagree silently -- `_validate_effective_spec`
|
|
401
|
+
# excludes lora_alpha from its structural comparison, leaving the digest as the only cover.
|
|
402
|
+
if self.public_omits_lora_alpha:
|
|
403
|
+
public_payload["train"].pop("lora_alpha", None)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _dropped_key_subset(raw_spec: object) -> dict[str, Any]:
|
|
407
|
+
"""The since-removed top-level keys a mapping carries, and nothing else.
|
|
408
|
+
|
|
409
|
+
Applied on the way in AND on the way out: a key the dataclass still defines must come from the
|
|
410
|
+
spec, never from a replayed reading, so the filter has to sit at the apply site too.
|
|
411
|
+
"""
|
|
412
|
+
if not isinstance(raw_spec, Mapping):
|
|
413
|
+
return {}
|
|
414
|
+
return {key: raw_spec[key] for key in DROPPED_TOP_LEVEL_KEYS if key in raw_spec}
|
{freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/backend_common.py
RENAMED
|
@@ -935,6 +935,7 @@ from flash.engine.worker.verl.capabilities import ( # noqa: E402,F401
|
|
|
935
935
|
resolve_rollout_enforce_eager,
|
|
936
936
|
resolve_verl_loggers,
|
|
937
937
|
resolve_verl_python,
|
|
938
|
+
rollout_mm_processor_cache_overrides,
|
|
938
939
|
rollout_resident_overrides,
|
|
939
940
|
rollout_sleep_unsupported,
|
|
940
941
|
strict_gdn_probe_module,
|