freesolo-flash-dev 1.2.28__tar.gz → 1.2.36__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- freesolo_flash_dev-1.2.36/CHANGELOG.md +113 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/__init__.py +2 -2
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/deploy.py +214 -1
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/episode.py +72 -30
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/eval.py +7 -4
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/setup.py +9 -7
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test.py +26 -20
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test_evaluations.py +58 -4
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/scaffold/TRAINING.md +7 -2
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/tables.py +3 -1
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/http.py +62 -18
- freesolo_flash_dev-1.2.36/flash/client/streaming.py +145 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/core/spec.py +106 -11
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/evaluations.py +41 -7
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/allocator.py +92 -58
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/__init__.py +16 -1
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/preparation.py +11 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/status.py +14 -2
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/submit.py +9 -4
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/attach.py +2 -5
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/lifecycle.py +8 -6
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/seed_submission.py +6 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/transitions.py +24 -3
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/schema/__init__.py +63 -55
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/deploy.py +17 -9
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/errors.py +16 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/app.py +3 -2
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/billing/charges.py +4 -3
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/run_registry.py +2 -3
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/runtime.py +2 -5
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving.py +3 -3
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving_completion.py +133 -59
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving_revisions.py +38 -7
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving_smoke.py +109 -29
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_allocator.py +83 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cancel_remote.py +53 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_commands.py +20 -1
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_render_coverage.py +30 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client.py +267 -6
- freesolo_flash_dev-1.2.36/tests/test_deploy_alias_move_warning.py +554 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_evaluations.py +92 -14
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_publish.py +56 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_test.py +370 -23
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_idle_endpoint_reaper.py +40 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_provider_routing.py +125 -31
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serve.py +11 -8
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_api.py +624 -47
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_envs_coverage.py +310 -5
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_spec_and_validation.py +205 -1
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/uv.lock +1 -1
- freesolo_flash_dev-1.2.28/CHANGELOG.md +0 -200
- freesolo_flash_dev-1.2.28/flash/client/streaming.py +0 -94
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.dockerignore +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.env.example +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/CODEOWNERS +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.gitignore +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/Dockerfile +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/LICENSE +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/NOTICE +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/README.md +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/SELF_HOSTING.md +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/deploy/infisical/README.md +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/deploy/infisical/entrypoint.sh +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/extract_cudart_fix.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/channel.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/fileio.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/logging.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/paths.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/adapters/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/adapters/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/adapters/lora_rank.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/eval_args.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/imports.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/list.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/push.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/retained.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test_params.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test_warnings.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/traces.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/train_cost.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/scaffold/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/cost.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/env_panels.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/render.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/tty.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/freesolo_api.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/shapes.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/multimodal.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/thinking.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/core/catalog.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/kv_sizing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/model_config_probe.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/recipe.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/steps.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/vram.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/reasoning_render.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/tokenizer.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/result/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/result/accounting.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/result/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/backend_common.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/opd.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/rl.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/sft.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/hf.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/prefetch.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/wandb_log.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/adapter.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/decoding.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/lora.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/packing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/opd_train.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/opd_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/rl_train.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/rl_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/rng.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/score_batcher.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/sft_train.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/sft_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/client.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/encoding.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/child/glue.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/step_timing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/finalize.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/batching.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/bridge.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/bridge.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/structured.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/failures.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/gkd.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/multiturn_validation.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/overrides.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/prompts.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/reporting.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/scoring.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/state.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/validation.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/config.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/inputs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/multi_turn.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/scoring.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/shims.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/single_turn.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/verl_config.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/sft/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/sft/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/sft/config.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/capabilities.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/child_io.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/parallelism.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/cache_security.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/dataset_selection.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/identity.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/namespace_listing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/package/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/package/limits.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/package/unpack.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/auth.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/bootstrap.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/bootstrap_pip.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/deadline.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/http.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/instance.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/poll.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/poll_instance.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/provider.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/worker.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/hf.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/preload_runpod.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/fit_errors.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/api.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/auth.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/gpus.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/jobs/reap.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/pricing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/job_execution.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/resources.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/serverless/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/serverless/endpoints.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/sharding.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/attempts.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/costs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/deadlines.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/reconciliation.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/results/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/results/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/results/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/deploy.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/recovery.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/retry_decision.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/adapter_check.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/responses.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/streaming.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/thinking.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/billing/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/billing/retry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/environment_registry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/envs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/projects.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/reconcile.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/teacher_errors.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/teacher_requests.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/auth.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/db.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/deps.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/internal_client.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/locks.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/teacher/limits.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/teacher/retry_contract.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/check_file_size.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/check_function_size.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/check_verl_pin_exists.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/profile.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/teacher.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_sft_thinking_render_live.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_adapter_shard_completeness.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_build_context_contract.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_catalog_only_models.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client_import_purity.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_config_env_vars.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_list_api.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_list_cli.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_list_hub.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_freesolo_api_transport.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_infisical_secrets.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_multiturn_eos_boundary.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_train.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_parasail_teacher.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_rl_train.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_startup_block.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_train.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_step_floor.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_step_timing.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_teacher_encoding_contract.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_type_comment_prose.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_thinking.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_workflow_contracts.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_zero2_sharding_gate.py +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to `freesolo-flash`. The dev-channel package `freesolo-flash-dev` ships in
|
|
4
|
+
lockstep at the same version.
|
|
5
|
+
|
|
6
|
+
Releases happen by merging a version bump from `dev` into `main`, which publishes to PyPI
|
|
7
|
+
(`.github/workflows/publish.yml`). Versions are `MAJOR.MINOR.PATCH`.
|
|
8
|
+
|
|
9
|
+
This file starts at 1.1.35. Earlier releases are not reconstructed here; use
|
|
10
|
+
`git log` for anything before that.
|
|
11
|
+
|
|
12
|
+
## Unreleased
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- A `flash-cli` console script, the same entry point as `flash` under a name nothing else
|
|
17
|
+
claims. The `server` and `dev` extras install `runpod-flash`, which declares its own `flash`
|
|
18
|
+
script; whichever distribution is installed last wins, so on a control-plane host
|
|
19
|
+
`pip install 'freesolo-flash[server]'` could leave `flash` running RunPod's CLI, which exits 0
|
|
20
|
+
and does nothing. `flash` is unchanged and remains correct on a base (client-only) install.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- CI runs the offline test suite on both supported interpreters (3.11 and 3.12) rather than
|
|
25
|
+
3.11 alone, and sets `HF_HUB_OFFLINE` / `TRANSFORMERS_OFFLINE` so a test that reaches the
|
|
26
|
+
network fails deterministically instead of depending on runner connectivity.
|
|
27
|
+
- Every GitHub Action is pinned to a commit SHA rather than a mutable tag.
|
|
28
|
+
- `mypy` runs in CI as an advisory (non-blocking) job.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- `flash models deploy` now warns before it moves the shared `<run-id>` model id onto a
|
|
33
|
+
different checkpoint. Every checkpoint of a run is served under that one id, so deploying
|
|
34
|
+
`<run-id>/step-50` while `step-100` was live silently changed what `<run-id>` served for
|
|
35
|
+
everyone using it — which made "deploy a second checkpoint to compare" a destructive
|
|
36
|
+
operation on the first, and read as a serving regression rather than the deploy that caused
|
|
37
|
+
it. The warning names both checkpoints and points at `flash models chat <run-id>/step-N`,
|
|
38
|
+
which addresses a checkpoint directly and does not depend on where the id points. It is
|
|
39
|
+
advisory: the deploy still proceeds, the pre-deploy read is abandoned outright once it exceeds
|
|
40
|
+
a few seconds so no shape of slow plane can hold a deploy behind it, and a control plane that
|
|
41
|
+
cannot answer (or answers with a checkpoint step this client cannot read) does not fail the
|
|
42
|
+
command. A deployment whose activation outcome was never settled still warns, but without
|
|
43
|
+
naming a checkpoint: that record's step describes the incoming attempt rather than what the id
|
|
44
|
+
currently serves, and the authoritative target is server-side only, so the warning says the
|
|
45
|
+
live checkpoint cannot be determined and points at `flash models deployments`.
|
|
46
|
+
|
|
47
|
+
- A response deadline did not actually bound a response that arrived slowly. The deadline is
|
|
48
|
+
checked between reads, but each read asked for a fixed number of bytes and blocked until all of
|
|
49
|
+
them arrived, so a peer trickling a short body kept one read inside the socket timeout
|
|
50
|
+
indefinitely and the check never ran: a 2s deadline took 12s on a 42-byte body, and 61s when
|
|
51
|
+
the socket timeout was the client default. Reading whatever has already arrived lets the check
|
|
52
|
+
run, which bounds every stall shape. This affected `flash env list`, whose deadline exists to
|
|
53
|
+
stop a slow environment hub hanging the command, as well as the new pre-deploy read.
|
|
54
|
+
|
|
55
|
+
- A response deadline could still be overrun by a read that began near its end. The socket timeout
|
|
56
|
+
is installed once, when the request opens, and time spent connecting and waiting for headers is
|
|
57
|
+
charged to the deadline but not to that timeout, so a peer that delayed its headers and then
|
|
58
|
+
stalled mid-body held the call open past the deadline: 3.5s against a 2s budget. Each read now
|
|
59
|
+
re-caps the socket to the remaining budget, so the two bounds agree instead of stacking. On a
|
|
60
|
+
body still arriving this surfaces as a timeout rather than the "stalled" message; both bound the
|
|
61
|
+
call, and which one wins is a race not worth depending on.
|
|
62
|
+
|
|
63
|
+
- Commands printed for the operator to run (the resume/cancel hand-off after `flash train`,
|
|
64
|
+
usage strings, `next:` hints) now name the executable actually invoked rather than always
|
|
65
|
+
`flash`. On a host where `runpod-flash` owns the `flash` script, the printed
|
|
66
|
+
`flash runs cancel <run-id>` exited 0 without cancelling, leaving a run billing while the
|
|
67
|
+
operator believed they had stopped it. Reached through the `python -m flash.cli` escape hatch,
|
|
68
|
+
the printed command now names the interpreter that is actually running, rather than a bare
|
|
69
|
+
`python` that is absent on a python3-only host and may resolve to a different environment
|
|
70
|
+
inside a virtualenv.
|
|
71
|
+
|
|
72
|
+
- `flash env setup` scaffolded hosted-only environment instructions on every plane. A
|
|
73
|
+
self-hosted plane cannot publish to Freesolo's managed environment hub, so the generated
|
|
74
|
+
configs left `[environment] id` empty (which fails validation) beside a `flash env push`
|
|
75
|
+
command that could not work. Against a self-hosted plane the scaffold now emits the
|
|
76
|
+
`github:owner/repo@ref:path` id form, which such a plane resolves directly. Output against
|
|
77
|
+
the managed plane is unchanged.
|
|
78
|
+
|
|
79
|
+
- `flash-server` reported missing operator configuration as an unhandled ASGI startup
|
|
80
|
+
exception, so the actionable message arrived under ~20 frames of starlette/contextlib. The
|
|
81
|
+
refusing half of the preflight now runs before uvicorn starts, and `flash-server` prints
|
|
82
|
+
`error: ...` and exits 3 (uvicorn's `STARTUP_FAILURE`, which this path already used, so
|
|
83
|
+
supervision keying on it is unaffected). The advisory warnings still come from the lifespan
|
|
84
|
+
alone, so a booted plane logs them once.
|
|
85
|
+
- `flash env test` blamed the reward function for a gold answer that scored zero, when the
|
|
86
|
+
gold completion is equally likely to be at fault: with no `sft_completion` hook the replayed
|
|
87
|
+
answer is the dataset row's raw `output`, so a dataset whose `output` is a bare value fails a
|
|
88
|
+
grader that (correctly) requires a wrapper. The warning now names both candidates and prints
|
|
89
|
+
the exact text it scored, verbatim rather than through the whitespace-collapsing, 200-character
|
|
90
|
+
preview that hid the formatting faults it exists to reveal. The scaffolded `environment.py`
|
|
91
|
+
documents that `output` is also the gold assistant turn SFT trains on, and that per-row scorer
|
|
92
|
+
state belongs in `metadata`.
|
|
93
|
+
- `flash env test` labelled the replayed dataset turns as the text that scored zero, but a
|
|
94
|
+
multi-turn environment whose `step_episode` returns a `final_response_text` has that override
|
|
95
|
+
replace the episode's response before scoring, so the diagnostic named text the grader never
|
|
96
|
+
saw. It now reports what the scorer actually received, captured at the scoring call.
|
|
97
|
+
- An environment that overrode its answer to the empty string had `flash env test` report the
|
|
98
|
+
replayed turns instead: the captured text was tested for truth, so a graded `""` was
|
|
99
|
+
indistinguishable from an episode that never reached the scorer. The override propagates on
|
|
100
|
+
`is not None`, so `""` really is what the grader saw -- and an empty answer explains a zero
|
|
101
|
+
reward on its own, making it the reading a reader most needs named rather than hidden.
|
|
102
|
+
- A crashed scorer went unreported on an `echo` episode -- a row with no gold answer to replay,
|
|
103
|
+
which is also the case that leaves the GRPO gate with nothing to count. `flash env test` could
|
|
104
|
+
exit `overall: PASS` with every reward coming from a scorer that never ran. The scorer's error is
|
|
105
|
+
now surfaced for any policy.
|
|
106
|
+
- A scorer that crashed behind the SDK's guard reached `flash env test` as a bare `0.000000`,
|
|
107
|
+
indistinguishable from a judged-wrong answer, because the adapter kept only
|
|
108
|
+
`RewardResult.score`. The new `FreesoloEnvironment.reward_with_error` returns the reward and the
|
|
109
|
+
discarded error from a single scoring call, so a missing runtime dependency names itself without
|
|
110
|
+
re-scoring the episode -- which would bill a paid judge twice and, for a non-deterministic
|
|
111
|
+
scorer, could report an error that did not produce the printed reward.
|
|
112
|
+
- Two tests resolved Hugging Face model metadata over the network and passed only on a
|
|
113
|
+
connected runner. They now stub the resolver like their siblings already did.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.36
|
|
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
|
|
@@ -738,11 +738,11 @@ def _add_deployment_commands(models_sub: argparse._SubParsersAction) -> None:
|
|
|
738
738
|
"--wait",
|
|
739
739
|
nargs="?",
|
|
740
740
|
type=_wait_seconds,
|
|
741
|
-
const=
|
|
741
|
+
const=2400.0,
|
|
742
742
|
default=None,
|
|
743
743
|
metavar="SECONDS",
|
|
744
744
|
help=(
|
|
745
|
-
"block until the requested revision is ready or failed (default timeout
|
|
745
|
+
"block until the requested revision is ready or failed (default timeout 2400s). "
|
|
746
746
|
"without it, deploy returns while the revision is still queued"
|
|
747
747
|
),
|
|
748
748
|
)
|
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
13
|
import sys
|
|
14
|
+
import threading
|
|
14
15
|
import time
|
|
15
16
|
|
|
16
17
|
from flash.cli.ui import render
|
|
@@ -41,6 +42,10 @@ _DEPLOYMENT_BUSY_STATES = frozenset({"queued", "smoke_testing", "reconciling"})
|
|
|
41
42
|
# plane introduces are both non-busy and non-servable, so `--wait` must fail closed on them
|
|
42
43
|
# rather than let `deploy --wait && evaluate` proceed against nothing.
|
|
43
44
|
_DEPLOYMENT_READY_STATES = frozenset({"ready", "deployed"})
|
|
45
|
+
# an undeploy whose backend cleanup failed (flash/runner/supervise/transitions.py). local serving
|
|
46
|
+
# authority is revoked, but the alias may still resolve to the old target -- neither servable nor
|
|
47
|
+
# safely assumed idle.
|
|
48
|
+
_REVOCATION_FAILED_STATE = "revocation_failed"
|
|
44
49
|
_DEPLOY_POLL_SECONDS = 5.0
|
|
45
50
|
# `--wait 0` still owes the caller its one read, and a read needs a positive timeout. keep that
|
|
46
51
|
# bound short enough that "check once, do not block" stays true against a stalled plane: a longer
|
|
@@ -57,6 +62,14 @@ _DEPLOY_FINAL_READ_FRACTION = 0.9
|
|
|
57
62
|
# an auth or authorization rejection answers the same way every time; polling through it just
|
|
58
63
|
# spends the whole timeout to arrive at the identical error.
|
|
59
64
|
_PERMANENT_POLL_STATUSES = frozenset({401, 403})
|
|
65
|
+
# the pre-deploy alias read is advisory, so it must not spend the client's default 60s budget
|
|
66
|
+
# deciding whether to print a warning: a stalled read would delay every real deploy behind a
|
|
67
|
+
# line nobody asked for. short enough to stay unnoticed, long enough for a healthy plane.
|
|
68
|
+
# it is spent three ways, because the client's own bounds are per-phase: as a socket timeout it
|
|
69
|
+
# bounds one socket operation, and as a body deadline it bounds the body but is only consulted
|
|
70
|
+
# once headers are parsed. a peer trickling headers just inside the socket timeout escapes both.
|
|
71
|
+
# `_read_within` bounds the total in wall-clock time, which is the one that actually holds.
|
|
72
|
+
_ALIAS_WARNING_READ_SECONDS = 5.0
|
|
60
73
|
|
|
61
74
|
|
|
62
75
|
def _await_deployment(client, run_id: str, deployment: dict, timeout: float) -> dict:
|
|
@@ -189,6 +202,196 @@ def _rollback_record(client, run_id: str, timeout: float) -> dict | None:
|
|
|
189
202
|
return None
|
|
190
203
|
|
|
191
204
|
|
|
205
|
+
def _served_step_label(step: int | None) -> str:
|
|
206
|
+
"""Name a deployment's checkpoint the way the user addressed it: `step-N`, or `final`."""
|
|
207
|
+
return "final" if step is None else f"step-{step}"
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _read_within(budget: float, read):
|
|
211
|
+
"""Run an advisory read, giving up on it entirely once ``budget`` seconds have passed.
|
|
212
|
+
|
|
213
|
+
The client's two bounds are both per-phase, not total: `timeout` restarts on every socket
|
|
214
|
+
operation and the body deadline is only checked once `urlopen` has finished parsing headers.
|
|
215
|
+
A peer that trickles the status line or headers just inside the socket timeout therefore
|
|
216
|
+
stalls for timeout x however many pauses it takes -- 12s against a 2s budget, measured -- and
|
|
217
|
+
the whole point of the bound is that the deploy the user actually asked for is waiting behind
|
|
218
|
+
it. Only wall-clock time outside the call bounds every phase at once.
|
|
219
|
+
|
|
220
|
+
A daemon thread rather than a cancellation: a blocked socket read cannot be interrupted from
|
|
221
|
+
outside, so the read is abandoned rather than stopped. That is sound only because this result
|
|
222
|
+
is discardable -- no warning is the documented outcome for a plane that cannot answer, so an
|
|
223
|
+
overrunning read degrades to silence. Daemon, so a stuck thread cannot keep the interpreter
|
|
224
|
+
alive after the deploy finishes.
|
|
225
|
+
"""
|
|
226
|
+
result: list = []
|
|
227
|
+
worker = threading.Thread(
|
|
228
|
+
target=lambda: result.append(_read_or_none(read)),
|
|
229
|
+
daemon=True,
|
|
230
|
+
)
|
|
231
|
+
worker.start()
|
|
232
|
+
worker.join(budget)
|
|
233
|
+
return result[0] if result else None
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _read_or_none(read):
|
|
237
|
+
"""The advisory read's failure contract: a plane that cannot answer produces no warning.
|
|
238
|
+
|
|
239
|
+
Deliberately broader than `ApiError`/`ClientError`. The client translates urllib's HTTPError
|
|
240
|
+
and URLError, and documents that anything else propagates -- so a connection reset or a
|
|
241
|
+
truncated body mid-read surfaces as the bare `ConnectionResetError` / `IncompleteRead` that
|
|
242
|
+
urllib raised. Those are exactly the "plane cannot answer" case this exists to absorb, and on
|
|
243
|
+
the worker thread an escaping one reaches the thread hook and prints a traceback across a
|
|
244
|
+
deploy that is otherwise proceeding normally: a warning nobody asked for turning into noise
|
|
245
|
+
on a command that worked.
|
|
246
|
+
"""
|
|
247
|
+
try:
|
|
248
|
+
return read()
|
|
249
|
+
except Exception:
|
|
250
|
+
# the deploy itself is the authority on whether it can proceed. failing it here -- or
|
|
251
|
+
# printing a traceback beside it -- would turn a warning nobody asked for into a fault in
|
|
252
|
+
# the command it decorates. BaseException still propagates, so KeyboardInterrupt is
|
|
253
|
+
# unaffected.
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _alias_move_warning(client, base_run_id: str, requested_step: int | None) -> str | None:
|
|
258
|
+
"""Warn when deploying moves the shared `<run_id>` alias off a different checkpoint.
|
|
259
|
+
|
|
260
|
+
`deploy` registers under the bare run id whatever step it is given, so deploying a second
|
|
261
|
+
checkpoint of the same run does not stand up a second endpoint -- it repoints the one alias,
|
|
262
|
+
and everyone chatting bare `<run_id>` silently changes model. That makes "deploy another
|
|
263
|
+
checkpoint to compare" a destructive operation on the first, which reads as a serving fault
|
|
264
|
+
rather than the deploy that caused it.
|
|
265
|
+
|
|
266
|
+
Best-effort by construction: the read is advisory, so a plane that cannot answer must not
|
|
267
|
+
stop the deploy. Returns None when nothing is being displaced -- no deployment, the same
|
|
268
|
+
checkpoint again, or an unreadable current record.
|
|
269
|
+
"""
|
|
270
|
+
current = _read_within(
|
|
271
|
+
_ALIAS_WARNING_READ_SECONDS,
|
|
272
|
+
# not `deployment_for`: its step filter hides exactly the record this asks about, a
|
|
273
|
+
# DIFFERENT checkpoint holding the alias.
|
|
274
|
+
lambda: client.deployed_checkpoint(
|
|
275
|
+
base_run_id,
|
|
276
|
+
timeout=_ALIAS_WARNING_READ_SECONDS,
|
|
277
|
+
body_deadline=_ALIAS_WARNING_READ_SECONDS,
|
|
278
|
+
),
|
|
279
|
+
)
|
|
280
|
+
if current is None:
|
|
281
|
+
return None
|
|
282
|
+
# a `reconciling` record whose activation outcome was never recorded may ALREADY hold the
|
|
283
|
+
# alias. the plane permits replacing exactly that record rather than rejecting it as busy,
|
|
284
|
+
# and resolves the authoritative target through `_activation_predecessor` when it does
|
|
285
|
+
# (flash/server/routes/serving.py). reading it as "not serving" suppressed the warning in
|
|
286
|
+
# the very case the alias is most likely to move out from under someone.
|
|
287
|
+
unknown_activation = current.get("activation_outcome_unknown") is True
|
|
288
|
+
# `revocation_failed` is an undeploy whose BACKEND cleanup failed: local authority is revoked
|
|
289
|
+
# but the alias may still resolve to the old target, and `_validate_deploy_request` rejects
|
|
290
|
+
# only the busy set, so a deploy proceeds from here. reading it as "not serving" suppressed
|
|
291
|
+
# the warning in the case where cleanup already left the alias ambiguous.
|
|
292
|
+
revocation_failed = str(current.get("state") or "") == _REVOCATION_FAILED_STATE
|
|
293
|
+
ambiguous = unknown_activation or revocation_failed
|
|
294
|
+
if str(current.get("state") or "") not in _DEPLOYMENT_READY_STATES and not ambiguous:
|
|
295
|
+
# nothing is being served off the alias yet, so nothing is lost by moving it.
|
|
296
|
+
return None
|
|
297
|
+
cli = _commands().CLI_NAME
|
|
298
|
+
# `step-N` is not universally available: `ApiClient.chat` gates a step target behind
|
|
299
|
+
# `_require_chat_step_selector`, which refuses outright on a plane that does not advertise
|
|
300
|
+
# `chat_step_selector_v1`. the capability cannot be read here without spending a /v1/health on
|
|
301
|
+
# an advisory warning, and `_chat_step_selector_available` starts False, so a negative reading
|
|
302
|
+
# cannot tell "unsupported" from "not checked yet". state the condition instead of asserting
|
|
303
|
+
# the command works, and name the selector that works on every plane.
|
|
304
|
+
tail = (
|
|
305
|
+
f"so every client using bare `{base_run_id}` changes model. address a specific "
|
|
306
|
+
f"checkpoint with `{cli} models chat {base_run_id}/step-N` to compare them, or by "
|
|
307
|
+
"immutable adapter revision if this control plane does not support step selectors."
|
|
308
|
+
)
|
|
309
|
+
if revocation_failed:
|
|
310
|
+
# same reason as the unknown-activation arm: this record's `checkpoint_step` describes the
|
|
311
|
+
# deployment whose revocation failed, and whether the backend still answers on the alias
|
|
312
|
+
# is exactly what could not be determined. hedge rather than name a checkpoint.
|
|
313
|
+
return (
|
|
314
|
+
f"{base_run_id} has a deployment whose revocation did not complete, so whether it "
|
|
315
|
+
f"still serves off that shared model id cannot be determined from here; deploying "
|
|
316
|
+
f"{_served_step_label(requested_step)} may move it, "
|
|
317
|
+
f"{tail} run `{cli} models deployments` to see the current state first."
|
|
318
|
+
)
|
|
319
|
+
if unknown_activation:
|
|
320
|
+
# this record's `checkpoint_step` names the INCOMING attempt, not what the alias holds:
|
|
321
|
+
# the plane resolves the live target from `adapter_alias_target` / `previous_deployment`,
|
|
322
|
+
# and both are server-side (`public_deployment` strips the predecessor). naming a
|
|
323
|
+
# checkpoint here would report the wrong one -- worse than naming none -- so say only what
|
|
324
|
+
# this side can actually stand behind.
|
|
325
|
+
return (
|
|
326
|
+
f"{base_run_id} has a deployment whose activation never settled, so the checkpoint "
|
|
327
|
+
f"it currently serves cannot be determined from here; deploying "
|
|
328
|
+
f"{_served_step_label(requested_step)} may move that shared model id, "
|
|
329
|
+
f"{tail} run `{cli} models deployments` to see the current state first."
|
|
330
|
+
)
|
|
331
|
+
raw_step = current.get("checkpoint_step")
|
|
332
|
+
# `int()` does not just reject what it cannot read -- it silently COERCES. `true` becomes 1,
|
|
333
|
+
# `false` becomes 0, and `1.5` truncates to 1, none of them raising. a step this client cannot
|
|
334
|
+
# read as an exact whole number is an unreadable record, not checkpoint 1: reading it as a
|
|
335
|
+
# number either suppresses the warning (deploying step-1 against a `true`) or names a
|
|
336
|
+
# checkpoint that was never live. bool is checked first because it is a subclass of int.
|
|
337
|
+
if isinstance(raw_step, bool):
|
|
338
|
+
return None
|
|
339
|
+
if isinstance(raw_step, float) and not raw_step.is_integer():
|
|
340
|
+
return None
|
|
341
|
+
try:
|
|
342
|
+
served_step = None if raw_step is None else int(raw_step)
|
|
343
|
+
except (TypeError, ValueError, OverflowError):
|
|
344
|
+
# a proxy or older plane can answer 2xx with a step this client cannot read. that is an
|
|
345
|
+
# unreadable current record like any other, NOT a reason to fail the deploy: leaving the
|
|
346
|
+
# conversion unguarded let an advisory read traceback out of the command it decorates.
|
|
347
|
+
# all three arms are reachable from one JSON body: `json.loads` accepts the non-standard
|
|
348
|
+
# `Infinity`/`NaN` literals, and int() answers those with OverflowError and ValueError
|
|
349
|
+
# respectively -- so catching only the obvious two still crashed the deploy.
|
|
350
|
+
return None
|
|
351
|
+
if served_step == requested_step:
|
|
352
|
+
return None
|
|
353
|
+
reach_displaced = ""
|
|
354
|
+
# the record being displaced carries the one identifier that survives the alias move, so name
|
|
355
|
+
# it whenever it is there. `step-N` is not a substitute: it is rejected outright on a plane
|
|
356
|
+
# without `chat_step_selector_v1`, and after this deploy the listing shows only the NEW record
|
|
357
|
+
# -- `public_deployment` strips `previous_deployment` (flash/serve/urls.py) -- so a revision
|
|
358
|
+
# not printed here is not recoverable from anywhere afterwards.
|
|
359
|
+
revision = str(current.get("adapter_revision") or "").strip()
|
|
360
|
+
if served_step is None:
|
|
361
|
+
# the displaced checkpoint is the FINAL adapter, and `_parse_chat_target` accepts only a
|
|
362
|
+
# bare run id, `RUN/step-N`, or a full immutable revision -- there is no `/final`
|
|
363
|
+
# selector. once the alias moves, `step-N` addresses the incoming checkpoint and the bare
|
|
364
|
+
# id is the thing that just changed, so the generic advice cannot reach the final adapter
|
|
365
|
+
# at all. its immutable revision can, and the record being displaced carries one.
|
|
366
|
+
reach_displaced = (
|
|
367
|
+
f" the displaced final adapter has no `/final` selector; reach it by its immutable "
|
|
368
|
+
f"revision `{revision}`."
|
|
369
|
+
if revision
|
|
370
|
+
# without a revision on the record there is nothing to hand the user, and deferring
|
|
371
|
+
# them to a later command would be worse than saying so: `client.deploy` fires as soon
|
|
372
|
+
# as this prints, and the deployments listing then shows only the NEW record --
|
|
373
|
+
# `public_deployment` strips `previous_deployment` (flash/serve/urls.py), so the
|
|
374
|
+
# displaced revision is not in it. promising a selector that the next command cannot
|
|
375
|
+
# produce is the one outcome worse than admitting there is none.
|
|
376
|
+
else (
|
|
377
|
+
" the displaced final adapter has no `/final` selector and this plane did not "
|
|
378
|
+
"report its immutable revision, so it will not be addressable after this deploy; "
|
|
379
|
+
"undeploy and redeploy it to serve it again."
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
elif revision:
|
|
383
|
+
# a numbered checkpoint keeps its `step-N` selector, but only on a plane that advertises
|
|
384
|
+
# `chat_step_selector_v1`; where it does not, the qualified advice above leaves the user
|
|
385
|
+
# holding no identifier at all. this is that identifier, and this is the last moment it
|
|
386
|
+
# can be printed.
|
|
387
|
+
reach_displaced = f" the displaced checkpoint's immutable revision is `{revision}`."
|
|
388
|
+
return (
|
|
389
|
+
f"{base_run_id} currently serves {_served_step_label(served_step)}; deploying "
|
|
390
|
+
f"{_served_step_label(requested_step)} moves that shared model id onto the new "
|
|
391
|
+
f"checkpoint, {tail}{reach_displaced}"
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
|
|
192
395
|
def _deployment_attempt_failed(requested: dict, final: dict) -> bool:
|
|
193
396
|
"""True when the requested revision is not the one now served.
|
|
194
397
|
|
|
@@ -229,8 +432,18 @@ def cmd_deploy(args) -> int:
|
|
|
229
432
|
file=sys.stderr,
|
|
230
433
|
)
|
|
231
434
|
return 1
|
|
232
|
-
base_run_id,
|
|
435
|
+
base_run_id, step = parsed
|
|
233
436
|
client = _commands().client_from_config()
|
|
437
|
+
# before the POST: after it the alias has already moved, and a warning about a checkpoint that
|
|
438
|
+
# is no longer served reads as history rather than a decision the reader still has. a dry run
|
|
439
|
+
# registers nothing, so it displaces nothing and gets no warning.
|
|
440
|
+
if not args.dry_run:
|
|
441
|
+
alias_warning = _alias_move_warning(client, base_run_id, step)
|
|
442
|
+
if alias_warning:
|
|
443
|
+
print(
|
|
444
|
+
render.warn(alias_warning) if render.styled() else f"warning: {alias_warning}",
|
|
445
|
+
file=sys.stderr,
|
|
446
|
+
)
|
|
234
447
|
dep = client.deploy(args.run_id, dry_run=args.dry_run)
|
|
235
448
|
wait_seconds = getattr(args, "wait", None)
|
|
236
449
|
# a dry run creates no deployment to poll for, so --wait has nothing to observe. test against
|
|
@@ -13,9 +13,11 @@ from __future__ import annotations
|
|
|
13
13
|
|
|
14
14
|
import contextlib
|
|
15
15
|
import inspect
|
|
16
|
+
import sys
|
|
16
17
|
|
|
17
18
|
from flash.cli.commands.env.test_evaluations import _evaluation_example
|
|
18
|
-
from flash.
|
|
19
|
+
from flash.cli.ui import render
|
|
20
|
+
from flash.envs.evaluations import EvalCase, EvalResult, _episode_grading_enabled
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
def _eval_module():
|
|
@@ -34,7 +36,7 @@ def _grades_episodes(suite) -> bool:
|
|
|
34
36
|
Keying off the environment scored the wrong turn there and turned a well-formed first action
|
|
35
37
|
into an error, so the suite has to say so itself.
|
|
36
38
|
"""
|
|
37
|
-
return
|
|
39
|
+
return _episode_grading_enabled(suite)
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
def _drive_episode(client, target: str, environment, case: EvalCase, args) -> dict | str:
|
|
@@ -123,7 +125,14 @@ def _effective_turn_cap(environment, state: dict) -> int:
|
|
|
123
125
|
|
|
124
126
|
|
|
125
127
|
def _score_episode_case(
|
|
126
|
-
suite,
|
|
128
|
+
suite,
|
|
129
|
+
case: EvalCase,
|
|
130
|
+
case_id: str,
|
|
131
|
+
state: dict,
|
|
132
|
+
*,
|
|
133
|
+
scorer,
|
|
134
|
+
state_style: str | None,
|
|
135
|
+
thinking: bool = False,
|
|
127
136
|
) -> EvalResult:
|
|
128
137
|
"""Grade a finished episode through the suite's own scorer.
|
|
129
138
|
|
|
@@ -134,18 +143,19 @@ def _score_episode_case(
|
|
|
134
143
|
`reward(completion, example, state)`, which is what reaches the SDK's `score_episodes`.
|
|
135
144
|
|
|
136
145
|
`EvalSuite.score(case, response)` is the published two-argument contract, so state is offered
|
|
137
|
-
only to a suite that accepts it
|
|
138
|
-
|
|
139
|
-
two-argument call and graded on the wrong text.
|
|
146
|
+
only to a suite that accepts it. The caller resolves one scorer and signature style for the
|
|
147
|
+
whole suite rather than retrying on TypeError: an error raised INSIDE a state-aware scorer must
|
|
148
|
+
not be retried as a two-argument call and graded on the wrong text.
|
|
140
149
|
"""
|
|
141
150
|
response = state.get("response_text")
|
|
142
151
|
if not isinstance(response, str):
|
|
143
152
|
turns = state.get("turns") or []
|
|
144
153
|
response = str(turns[-1]) if turns else ""
|
|
145
154
|
eval_module = _eval_module()
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
if state_style is None:
|
|
156
|
+
return eval_module._score_case(
|
|
157
|
+
suite, case, case_id, response, thinking=thinking, scorer=scorer
|
|
158
|
+
)
|
|
149
159
|
return eval_module._score_case(
|
|
150
160
|
suite,
|
|
151
161
|
case,
|
|
@@ -153,7 +163,8 @@ def _score_episode_case(
|
|
|
153
163
|
response,
|
|
154
164
|
thinking=thinking,
|
|
155
165
|
state=state,
|
|
156
|
-
state_keyword=
|
|
166
|
+
state_keyword=state_style == "keyword",
|
|
167
|
+
scorer=scorer,
|
|
157
168
|
)
|
|
158
169
|
|
|
159
170
|
|
|
@@ -173,27 +184,45 @@ def _state_argument(score) -> str | None:
|
|
|
173
184
|
except (TypeError, ValueError):
|
|
174
185
|
# builtins and C callables expose no signature; treat them as the published contract.
|
|
175
186
|
return None
|
|
176
|
-
named_state = next((p for p in parameters if p.name == "state"), None)
|
|
177
|
-
if named_state is not None and named_state.kind in (
|
|
178
|
-
inspect.Parameter.KEYWORD_ONLY,
|
|
179
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
180
|
-
):
|
|
181
|
-
# By keyword even where positional would also bind: it cannot land on the wrong parameter.
|
|
182
|
-
return "keyword"
|
|
183
|
-
# Checked before `*args`, since a scorer with both can take `state=` but one with only
|
|
184
|
-
# `*args` cannot.
|
|
185
|
-
if any(p.kind is inspect.Parameter.VAR_KEYWORD for p in parameters):
|
|
186
|
-
return "keyword"
|
|
187
|
-
if any(p.kind is inspect.Parameter.VAR_POSITIONAL for p in parameters):
|
|
188
|
-
return "positional"
|
|
189
187
|
positional = [
|
|
190
|
-
|
|
191
|
-
for
|
|
192
|
-
if
|
|
188
|
+
parameter
|
|
189
|
+
for parameter in parameters
|
|
190
|
+
if parameter.kind
|
|
191
|
+
in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)
|
|
193
192
|
]
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
193
|
+
named_state = next((parameter for parameter in parameters if parameter.name == "state"), None)
|
|
194
|
+
if named_state is not None:
|
|
195
|
+
if named_state.kind is inspect.Parameter.POSITIONAL_ONLY:
|
|
196
|
+
return "positional" if positional.index(named_state) == 2 else None
|
|
197
|
+
if named_state.kind in (
|
|
198
|
+
inspect.Parameter.KEYWORD_ONLY,
|
|
199
|
+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
200
|
+
):
|
|
201
|
+
# by keyword even where positional would also bind: it cannot land on the wrong parameter.
|
|
202
|
+
return "keyword"
|
|
203
|
+
# checked before `*args`, since a scorer with both can take `state=` but one with only
|
|
204
|
+
# `*args` cannot.
|
|
205
|
+
if any(parameter.kind is inspect.Parameter.VAR_KEYWORD for parameter in parameters):
|
|
206
|
+
return "keyword"
|
|
207
|
+
if any(parameter.kind is inspect.Parameter.VAR_POSITIONAL for parameter in parameters):
|
|
208
|
+
# scorer(case, response, state) reaches *args when the signature has no fixed third slot.
|
|
209
|
+
# zero, one, or two regular positional parameters can all bind that call.
|
|
210
|
+
return "positional" if len(positional) <= 2 else None
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _warn_if_episode_state_is_hidden(suite, state_style: str | None) -> None:
|
|
215
|
+
"""Warn once when full-episode work feeds a scorer that cannot see the transcript."""
|
|
216
|
+
if state_style is not None:
|
|
217
|
+
return
|
|
218
|
+
message = (
|
|
219
|
+
f"suite {getattr(suite, 'name', 'evaluation')!r} sets grades_episodes = True; "
|
|
220
|
+
"each episode will still be played out with one generation per turn, but the scorer "
|
|
221
|
+
"will receive only the episode's final response text, not the transcript. Add a third "
|
|
222
|
+
"`state` argument to "
|
|
223
|
+
"`score(case, response, state)` to grade the transcript."
|
|
224
|
+
)
|
|
225
|
+
print(render.warn(message) if render.styled() else f"warning: {message}", file=sys.stderr)
|
|
197
226
|
|
|
198
227
|
|
|
199
228
|
def _run_episode_cases(
|
|
@@ -220,6 +249,9 @@ def _run_episode_cases(
|
|
|
220
249
|
)
|
|
221
250
|
for case_id in case_ids
|
|
222
251
|
)
|
|
252
|
+
scorer = getattr(suite, "score", None)
|
|
253
|
+
state_style = _state_argument(scorer)
|
|
254
|
+
_warn_if_episode_state_is_hidden(suite, state_style)
|
|
223
255
|
results = []
|
|
224
256
|
# The adapter defaults to `thinking = False` (flash/envs/adapter.py), and with it off
|
|
225
257
|
# `_scored_turn_text` returns the turn unstripped -- so `state["response_text"]` keeps its
|
|
@@ -237,7 +269,17 @@ def _run_episode_cases(
|
|
|
237
269
|
if isinstance(outcome, str):
|
|
238
270
|
results.append(eval_module._generation_error(case_id, outcome))
|
|
239
271
|
continue
|
|
240
|
-
results.append(
|
|
272
|
+
results.append(
|
|
273
|
+
_score_episode_case(
|
|
274
|
+
suite,
|
|
275
|
+
case,
|
|
276
|
+
case_id,
|
|
277
|
+
outcome,
|
|
278
|
+
scorer=scorer,
|
|
279
|
+
state_style=state_style,
|
|
280
|
+
thinking=thinking,
|
|
281
|
+
)
|
|
282
|
+
)
|
|
241
283
|
return tuple(results)
|
|
242
284
|
|
|
243
285
|
|
|
@@ -162,6 +162,7 @@ def _score_case(
|
|
|
162
162
|
thinking: bool = False,
|
|
163
163
|
state=None,
|
|
164
164
|
state_keyword: bool = False,
|
|
165
|
+
scorer=None,
|
|
165
166
|
) -> EvalResult:
|
|
166
167
|
"""Grade one response on the caller's thread.
|
|
167
168
|
|
|
@@ -172,7 +173,8 @@ def _score_case(
|
|
|
172
173
|
`episode._score_episode_case`); single-turn scoring keeps the two-argument contract.
|
|
173
174
|
`state_keyword` says which way that suite's signature can take it -- `**kwargs` and
|
|
174
175
|
keyword-only scorers reject a third positional, `*args` scorers reject the keyword -- so the
|
|
175
|
-
caller decides, having read the signature.
|
|
176
|
+
caller decides, having read the signature. Episode scoring also passes the exact callable it
|
|
177
|
+
inspected, so a descriptor cannot change shape between capability detection and invocation.
|
|
176
178
|
|
|
177
179
|
The scorer grades the stripped answer; the RESULT records the raw generation. Stripping for the
|
|
178
180
|
scorer must not shorten what is recorded, on the error path least of all -- a failed case is
|
|
@@ -182,12 +184,13 @@ def _score_case(
|
|
|
182
184
|
try:
|
|
183
185
|
scored_text = _scored_response(response, thinking=thinking)
|
|
184
186
|
recorded_response = getattr(scored_text, "raw", response)
|
|
187
|
+
score = suite.score if scorer is None else scorer
|
|
185
188
|
if state is None:
|
|
186
|
-
scored =
|
|
189
|
+
scored = score(case, scored_text)
|
|
187
190
|
elif state_keyword:
|
|
188
|
-
scored =
|
|
191
|
+
scored = score(case, scored_text, state=state)
|
|
189
192
|
else:
|
|
190
|
-
scored =
|
|
193
|
+
scored = score(case, scored_text, state)
|
|
191
194
|
return normalize_eval_result(case, recorded_response, scored, case_id=case_id)
|
|
192
195
|
except (Exception, SystemExit) as exc:
|
|
193
196
|
return EvalResult(
|
|
@@ -138,12 +138,14 @@ Given the opening prompt, does the model emit the single integer `step_episode`
|
|
|
138
138
|
to advance the game? That is a real held-out check of the action format the episode
|
|
139
139
|
depends on, and it is the honest scope of a single-shot evaluation.
|
|
140
140
|
|
|
141
|
-
To grade a finished transcript instead, set `grades_episodes = True` on the suite
|
|
142
|
-
`env eval` then plays each case out
|
|
143
|
-
the
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
To grade a finished transcript instead, set `grades_episodes = True` on the suite
|
|
142
|
+
and define `score(self, case, response, state)`. `env eval` then plays each case out
|
|
143
|
+
against the deployed model -- generating, stepping the environment, and repeating to
|
|
144
|
+
`max_episode_turns` -- and passes the resulting transcript in `state`; without that
|
|
145
|
+
argument the scorer receives only the episode's final response text. Such a suite
|
|
146
|
+
needs cases the environment can actually advance (the cases below carry no `output`,
|
|
147
|
+
so `step_episode` has no secret to compare against), and each case then costs one
|
|
148
|
+
generation per turn rather than one in total.
|
|
147
149
|
|
|
148
150
|
Do NOT grade these by calling `environment.reward(response, example)`: with no episode
|
|
149
151
|
state that call scores an empty transcript, so an unrelated answer can score 1.0 and
|
|
@@ -289,7 +291,7 @@ class StarterMultiTurnEnv(EnvironmentMultiTurn):
|
|
|
289
291
|
# Advance the world after one assistant action. Return done=True to end the
|
|
290
292
|
# episode, or append an observation message and keep going.
|
|
291
293
|
# `messages` already ends with this action: messages[-1]["content"] is
|
|
292
|
-
# `assistant_response`.
|
|
294
|
+
# `assistant_response`. if you rebuild state by replaying the transcript, replay
|
|
293
295
|
# `messages[:-1]` and apply `assistant_response` once, or you apply it twice.
|
|
294
296
|
try:
|
|
295
297
|
guess = int(assistant_response.strip().split()[0])
|