freesolo-flash-dev 1.2.70__tar.gz → 1.2.88__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.70 → freesolo_flash_dev-1.2.88}/Dockerfile.worker +12 -5
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/adapters/fused_experts.py +30 -28
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/scaffold/TRAINING.md +5 -0
- freesolo_flash_dev-1.2.88/flash/content/image_descriptors.py +363 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/content/multimodal.py +261 -240
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/core/spec.py +88 -7
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/plan/vram.py +28 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/image_tokens.py +16 -10
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/__init__.py +36 -10
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/backend_common.py +1 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/entry/sft.py +2 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/opd_train.py +37 -8
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/opd_train_runner.py +73 -3
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/perf/__init__.py +4 -3
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/rl_train.py +5 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/rl_train_runner.py +6 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/sft_train.py +18 -4
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/sft_train_runner.py +7 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/core/child/glue.py +455 -30
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/core/child/runtime.py +34 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/bridge.py +126 -99
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/bridge.py +167 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/multiturn.py +62 -22
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/replay_guard.py +12 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/failures.py +8 -0
- freesolo_flash_dev-1.2.88/flash/engine/worker/train/opd/multiturn_media.py +129 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/overrides.py +11 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/prompts.py +8 -6
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/scoring.py +11 -9
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/state.py +2 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/child/multiturn.py +127 -74
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/child/patches.py +6 -24
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/inputs.py +10 -8
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/multi_turn.py +243 -87
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/verl_config.py +11 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/sft/checkpoints.py +13 -7
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/sft/child/plugin.py +4 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/verl/capabilities.py +35 -4
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/adapter.py +3 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/base.py +4 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/identity.py +12 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/loader.py +114 -23
- freesolo_flash_dev-1.2.88/flash/envs/staged.py +490 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/bootstrap.py +2 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/bootstrap_pip.py +1 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/worker.py +2 -4
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/serverless/endpoints.py +3 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/__init__.py +1 -5
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/artifacts.py +114 -5
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/preparation.py +50 -11
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/submit.py +1 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/attach.py +27 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/lifecycle.py +52 -52
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/seed_submission.py +1 -12
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/schema/__init__.py +3 -3
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/deploy.py +6 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/platform/deps.py +4 -6
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/serving_revisions.py +21 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/serving_smoke.py +160 -26
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_controlled_experiment_repairs.py +34 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_dataset_profile.py +1 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_evaluations.py +23 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_rate_limit_resolve.py +15 -23
- freesolo_flash_dev-1.2.88/tests/test_env_ref_pinning.py +73 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_flash_worker.py +19 -6
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_fused_expert_warmstart.py +148 -21
- freesolo_flash_dev-1.2.88/tests/test_image_environment_capability.py +92 -0
- freesolo_flash_dev-1.2.88/tests/test_image_incremental_processor.py +583 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_image_tokens.py +10 -15
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_jobs.py +1 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_lambda_runner.py +19 -7
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_multi_gpu_gate.py +103 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_multimodal_training.py +404 -21
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_opd.py +173 -8
- freesolo_flash_dev-1.2.88/tests/test_opd_multiturn_failure_exit.py +449 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_opd_replay_guard.py +24 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_opd_train.py +542 -15
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_persisted_spec_envelope.py +2 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_provider_routing.py +46 -40
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_rl_train.py +714 -59
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_serve.py +34 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_api.py +25 -4
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_billing.py +10 -9
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_envs_coverage.py +472 -14
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_sft_train.py +105 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_spec_and_validation.py +232 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_spec_contract_bytes.py +2 -1
- freesolo_flash_dev-1.2.88/tests/test_staged_environment.py +914 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_teacher_broker.py +0 -10
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_verifiers.py +1 -1
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_verl_checkpoint_export.py +67 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_warmstart_adapter_download.py +43 -0
- freesolo_flash_dev-1.2.88/tests/test_warmstart_image_adapters.py +223 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_worker_stack.py +80 -21
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/uv.lock +7 -7
- freesolo_flash_dev-1.2.70/tests/test_env_ref_pinning.py +0 -313
- freesolo_flash_dev-1.2.70/tests/test_opd_multiturn_failure_exit.py +0 -170
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.dockerignore +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.env.example +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/CODEOWNERS +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/dev-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/production-kernel-cache-ready.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/.gitignore +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/CHANGELOG.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/Dockerfile +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/LICENSE +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/NOTICE +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/README.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/SELF_HOSTING.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/deploy/infisical/README.md +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/deploy/infisical/entrypoint.sh +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/docker/extract_cudart_fix.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/_internal/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/_internal/channel.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/_internal/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/_internal/fileio.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/_internal/logging.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/_internal/paths.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/adapters/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/adapters/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/adapters/lora_rank.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/deploy.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/episode.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/eval.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/eval_args.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/imports.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/list.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/push.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/retained.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/setup.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/setup_wandb.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/test.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/test_evaluations.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/test_params.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/env/test_warnings.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/traces.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/commands/train_cost.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/scaffold/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/ui/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/ui/cost.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/ui/env_panels.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/ui/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/ui/render.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/ui/tables.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cli/ui/tty.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/freesolo_api.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/shapes.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/client/streaming.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/content/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/content/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/content/thinking.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/core/catalog.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/core/spec_persistence.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/huggingface.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/plan/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/plan/kv_sizing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/plan/model_config_probe.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/plan/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/plan/recipe.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/plan/steps.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/reasoning_render.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/sft_image_rows.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/tokenizer.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/profiling/workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/result/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/result/accounting.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/result/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/entry/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/entry/opd.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/entry/rl.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/io/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/io/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/io/hf.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/io/prefetch.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/io/wandb_log.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/model/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/model/adapter.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/model/chatml_mask.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/model/decoding.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/model/lora.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/model/packing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/runtime/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/runtime/rng.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/score_batcher.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/teacher/client.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/teacher/encoding.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/core/checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/core/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/core/step_timing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/finalize.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/batching.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/bridge_failures.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/runtime.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/child/structured.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/gkd.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/multiturn_validation.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/reporting.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/opd/validation.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/config.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/reward_module.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/scoring.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/rl/single_turn.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/sft/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/sft/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/train/sft/config.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/verl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/verl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/verl/child_io.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/verl/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/verl/parallelism.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker/verl/parent_work.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/cache_security.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/dataset_selection.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/namespace_listing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/package/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/package/direct_tokens.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/package/limits.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/package/unpack.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/auth.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/bootstrap_console.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/deadline.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/host/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/host/deadline_sleep.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/host/failmark.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/host/hostlog.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/http.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/instance.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/poll.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/poll_instance.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/provider.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/_lifecycle/terminal_artifacts.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/artifacts/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/artifacts/hf.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/artifacts/preload_runpod.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/artifacts/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/fit_errors.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/api.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/auth.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/gpus.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/jobs/reap.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/lambda_/pricing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/job_execution.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/resources.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/runpod/serverless/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/sharding.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/attempts.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/costs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/deadlines.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/reconciliation.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/results/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/results/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/results/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/status.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/deploy.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/recovery.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/retry_decision.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/supervise/transitions.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runner/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runtime_capsule/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runtime_capsule/build.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runtime_capsule/manifest.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/runtime_capsule/profiles.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/adapter_check.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/errors.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/responses.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/streaming.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/thinking.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/billing/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/billing/charges.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/billing/retry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/environment_registry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/envs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/projects.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/reconcile.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/run_registry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/teacher_errors.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/domain/teacher_requests.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/platform/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/platform/auth.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/platform/db.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/platform/internal_client.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/platform/locks.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/platform/runtime.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/serving_completion.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/source_snapshot.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/teacher/limits.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/flash/teacher/retry_contract.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/scripts/check_file_size.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/scripts/check_function_size.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/scripts/check_verl_pin_exists.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/_helpers/profile.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/_helpers/source_snapshot.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/_helpers/teacher.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/capture_image_sft_processor_oracle.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/fixtures/image_sft_processor_oracle.json +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/live/test_sft_thinking_render_live.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_adapter_shard_completeness.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_build_context_contract.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_catalog_only_models.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_client_import_purity.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_config_env_vars.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_console_upload.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_deploy_alias_move_warning.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_list_api.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_list_cli.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_list_hub.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_freesolo_api_transport.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_image_sft_markers.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_image_sft_processor_parity.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_infisical_secrets.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_opd_multiturn_eos_boundary.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_parasail_teacher.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_runtime_capsule.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_sft_startup_block.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_source_attestation_flow.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_source_snapshot.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_step_floor.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_step_timing.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_teacher_encoding_contract.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_terminal_artifacts.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_type_comment_prose.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_verl_child_plugins.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_verl_silence_watchdog.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_worker_thinking.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_workflow_contracts.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.70 → freesolo_flash_dev-1.2.88}/tests/test_zero2_sharding_gate.py +0 -0
|
@@ -59,15 +59,15 @@ RUN pip install --no-cache-dir \
|
|
|
59
59
|
"wandb>=0.17" \
|
|
60
60
|
"flash-linear-attention @ git+https://github.com/fla-org/flash-linear-attention.git@9c8e42e762fce087c27b673af4922795d9edb85e" \
|
|
61
61
|
"flash-qla==0.1.2" \
|
|
62
|
-
"tilelang==0.1.
|
|
63
|
-
"apache-tvm-ffi==0.1.
|
|
62
|
+
"tilelang==0.1.9" \
|
|
63
|
+
"apache-tvm-ffi==0.1.9" \
|
|
64
64
|
"hf_transfer" \
|
|
65
65
|
"freesolo>=0.4.1" \
|
|
66
66
|
"runpod"
|
|
67
67
|
# Gated-DeltaNet (Qwen3.5/3.6) runs on flash-linear-attention's Triton kernels. On consumer cards
|
|
68
68
|
# (Ampere/Ada/Blackwell) the Triton path is correct. On Hopper (sm90) fla's GDN chunk_bwd is
|
|
69
69
|
# miscomputed with Triton>=3.4 (fla #640) — the fix is fla's TILELANG backend (correct there), so
|
|
70
|
-
# we bake the pinned tilelang==0.1.
|
|
70
|
+
# we bake the pinned tilelang==0.1.9 + apache-tvm-ffi==0.1.9 (0.1.12 double-registers TVM-FFI ->
|
|
71
71
|
# `import tilelang` aborts) and KEEP fla on every arch; flash.engine.worker.perf._ensure_fla_fastpath_on_hopper
|
|
72
72
|
# ensures the tilelang backend is live on sm90 before any model import. The INVERSE holds on
|
|
73
73
|
# B200/sm100: THERE the tilelang chunk_bwd_dqkwg miscomputes gradients while the Triton path is
|
|
@@ -79,6 +79,13 @@ RUN pip install --no-cache-dir \
|
|
|
79
79
|
# seq16384 12.6x / 1.9x, loss matches to 1.8e-4. fla is from git: the PyPI wheel is a broken stub
|
|
80
80
|
# (no fla.modules). The git URL is PINNED to a commit (not the moving default branch) for
|
|
81
81
|
# reproducible image builds; keep this sha in lockstep with the worker dependencies in flash/providers/_lifecycle/worker.py.
|
|
82
|
+
# tilelang is 0.1.9, not the newest release: flash-qla (added for the sm90 GDN backend) hard-requires
|
|
83
|
+
# tilelang==0.1.9 AND apache-tvm-ffi==0.1.9, so 0.1.11 made this layer unsatisfiable and every image
|
|
84
|
+
# build failed from 2026-08-12 until the downgrade. 0.1.11 was only ever "latest stable at the time"
|
|
85
|
+
# (the pin exists for determinism, not to dodge a 0.1.9 defect), and the version predates flash-qla.
|
|
86
|
+
# Keep all four sites in lockstep -- both installs here, capabilities.py, and perf's TILELANG_PIN --
|
|
87
|
+
# because perf fails CLOSED: a resolved version != TILELANG_PIN deletes fla and drops sm90 to the
|
|
88
|
+
# pure-PyTorch fallback, which is correct but far slower.
|
|
82
89
|
|
|
83
90
|
# FlashAttention: PREFER a prebuilt wheel. There is no OFFICIAL Dao-AILab wheel for torch 2.10 yet,
|
|
84
91
|
# but community CI publishes matching wheels (cu128/torch2.10/cp312); CI passes one as FLASH_ATTN_SPEC
|
|
@@ -334,8 +341,8 @@ RUN printf '%s\n' "numpy==2.2.6" "xgrammar==0.1.25" "vllm==0.19.1" "transformers
|
|
|
334
341
|
cachetools uvicorn fastapi torchvision tqdm pyarrow \
|
|
335
342
|
"flash-linear-attention @ git+https://github.com/fla-org/flash-linear-attention.git@9c8e42e762fce087c27b673af4922795d9edb85e" \
|
|
336
343
|
"flash-qla==0.1.2" \
|
|
337
|
-
"tilelang==0.1.
|
|
338
|
-
"apache-tvm-ffi==0.1.
|
|
344
|
+
"tilelang==0.1.9" \
|
|
345
|
+
"apache-tvm-ffi==0.1.9" \
|
|
339
346
|
&& rm -f /tmp/verl-overrides.txt \
|
|
340
347
|
&& uv cache clean
|
|
341
348
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.88
|
|
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
|
|
@@ -14,6 +14,8 @@ from flash.adapters.lora_rank import (
|
|
|
14
14
|
)
|
|
15
15
|
from flash.core.catalog import get_model
|
|
16
16
|
|
|
17
|
+
_LORA_FACTOR_PATTERN = re.compile(r"\.lora_[AB]\.")
|
|
18
|
+
_LORA_PARAMETER = "weight"
|
|
17
19
|
_QWEN36_MODEL_ID = "Qwen/Qwen3.6-35B-A3B"
|
|
18
20
|
_QWEN36_EXPERT_TARGET_PARAMETERS = (
|
|
19
21
|
"mlp.experts.gate_up_proj",
|
|
@@ -31,7 +33,7 @@ _FUSED_EXPERT_SYNTHETIC_MODULES = frozenset({"experts", "base_layer"})
|
|
|
31
33
|
_FUSED_EXPERT_WRAPPER_MODULES = ("mlp.experts", "mlp.experts.base_layer")
|
|
32
34
|
_INVALID_FUSED_LOCATION = object()
|
|
33
35
|
|
|
34
|
-
_LoraTensor = tuple[str, str, str,
|
|
36
|
+
_LoraTensor = tuple[str, str, str, tuple[int, ...]]
|
|
35
37
|
_LoraPair = tuple[tuple[int, ...], tuple[int, ...]]
|
|
36
38
|
|
|
37
39
|
|
|
@@ -166,12 +168,13 @@ def has_complete_fused_expert_tensors(
|
|
|
166
168
|
expected = _expected_fused_expert_rungs(config, model_id)
|
|
167
169
|
if expected is None:
|
|
168
170
|
return False
|
|
171
|
+
lora_keys = {key: shape for key, shape in tensors.items() if _LORA_FACTOR_PATTERN.search(key)}
|
|
169
172
|
parsed = [
|
|
170
173
|
tensor
|
|
171
|
-
for key, shape in
|
|
174
|
+
for key, shape in lora_keys.items()
|
|
172
175
|
if (tensor := _parse_lora_tensor(key, shape)) is not None
|
|
173
176
|
]
|
|
174
|
-
if len(
|
|
177
|
+
if len(parsed) != len(lora_keys):
|
|
175
178
|
return False
|
|
176
179
|
return _has_complete_fused_rungs(parsed, expected, model_id) and _has_ordinary_evidence(
|
|
177
180
|
parsed, config, expected
|
|
@@ -179,7 +182,17 @@ def has_complete_fused_expert_tensors(
|
|
|
179
182
|
|
|
180
183
|
|
|
181
184
|
def _parse_lora_tensor(key: str, shape: tuple[int, ...]) -> _LoraTensor | None:
|
|
182
|
-
"""Parse one canonical PEFT LoRA tensor key.
|
|
185
|
+
"""Parse one canonical PEFT LoRA tensor key.
|
|
186
|
+
|
|
187
|
+
Accept exactly the grammar PEFT writes: a bare ``lora_A.weight`` leaf with no adapter
|
|
188
|
+
namespace. ``get_peft_model_state_dict`` documents stripping the namespace on save, verl's
|
|
189
|
+
merger reproduces that strip, and ``_insert_adapter_name_into_state_dict`` re-inserts it on
|
|
190
|
+
load, so the stripped form is the only spelling that round-trips. Verified against peft 0.19.1:
|
|
191
|
+
``...lora_A.weight`` loads as ``...lora_A.default.weight`` and matches the live module, while a
|
|
192
|
+
file that already carries the namespace loads as ``...lora_A.default.default.weight`` and
|
|
193
|
+
matches nothing. Since one grammar is accepted, the adapter namespace is no longer part of the
|
|
194
|
+
parsed identity.
|
|
195
|
+
"""
|
|
183
196
|
matches = [
|
|
184
197
|
(factor, infix) for factor, infix in (("A", ".lora_A."), ("B", ".lora_B.")) if infix in key
|
|
185
198
|
]
|
|
@@ -187,13 +200,9 @@ def _parse_lora_tensor(key: str, shape: tuple[int, ...]) -> _LoraTensor | None:
|
|
|
187
200
|
return None
|
|
188
201
|
factor, infix = matches[0]
|
|
189
202
|
module_path, _, leaf = key.partition(infix)
|
|
190
|
-
|
|
191
|
-
if not module_path or len(leaf_parts) != 2:
|
|
203
|
+
if not module_path or module_path.endswith(".") or leaf != _LORA_PARAMETER:
|
|
192
204
|
return None
|
|
193
|
-
|
|
194
|
-
if not adapter_name or parameter != "weight":
|
|
195
|
-
return None
|
|
196
|
-
return module_path, factor, adapter_name, key, shape
|
|
205
|
+
return module_path, factor, key, shape
|
|
197
206
|
|
|
198
207
|
|
|
199
208
|
def _expected_fused_expert_rungs(
|
|
@@ -237,31 +246,25 @@ def _expected_fused_expert_rungs(
|
|
|
237
246
|
def _has_complete_fused_rungs(
|
|
238
247
|
tensors: list[_LoraTensor], expected: Mapping[str, Mapping[str, _LoraPair]], model_id: str
|
|
239
248
|
) -> bool:
|
|
240
|
-
"""Validate every concrete fused owner, rung,
|
|
249
|
+
"""Validate every concrete fused owner, rung, and factor shape."""
|
|
241
250
|
model = get_model(model_id)
|
|
242
251
|
for owner, expected_rungs in expected.items():
|
|
243
|
-
factors: dict[str, dict[str, dict[str,
|
|
244
|
-
for module_path, factor,
|
|
252
|
+
factors: dict[str, dict[str, dict[str, tuple[int, ...]]]] = {}
|
|
253
|
+
for module_path, factor, _key, shape in tensors:
|
|
245
254
|
location = _fused_tensor_location(module_path, owner, frozenset(expected_rungs))
|
|
246
255
|
if location is _INVALID_FUSED_LOCATION:
|
|
247
256
|
return False
|
|
248
257
|
if location is None:
|
|
249
258
|
continue
|
|
250
259
|
instance, rung = location
|
|
251
|
-
factors.setdefault(instance, {}).setdefault(rung, {})
|
|
252
|
-
factor
|
|
253
|
-
] = shape
|
|
260
|
+
factors.setdefault(instance, {}).setdefault(rung, {})[factor] = shape
|
|
254
261
|
if not factors:
|
|
255
262
|
return False
|
|
256
263
|
for seen_rungs in factors.values():
|
|
257
264
|
if set(seen_rungs) != set(expected_rungs):
|
|
258
265
|
return False
|
|
259
266
|
for rung, expected_pair in expected_rungs.items():
|
|
260
|
-
|
|
261
|
-
if len(namespaces) != 1:
|
|
262
|
-
return False
|
|
263
|
-
seen_factors = next(iter(namespaces.values()))
|
|
264
|
-
if _lora_pair_shapes(seen_factors) != expected_pair:
|
|
267
|
+
if _lora_pair_shapes(seen_rungs[rung]) != expected_pair:
|
|
265
268
|
return False
|
|
266
269
|
expert_layers = {
|
|
267
270
|
prefix
|
|
@@ -303,28 +306,27 @@ def _has_ordinary_evidence(
|
|
|
303
306
|
config: Mapping[str, Any],
|
|
304
307
|
fused_rungs: Mapping[str, Mapping[str, _LoraPair]],
|
|
305
308
|
) -> bool:
|
|
306
|
-
"""Validate concrete ordinary target evidence with per-module ranks
|
|
309
|
+
"""Validate concrete ordinary target evidence with per-module ranks."""
|
|
307
310
|
modules = config.get("target_modules")
|
|
308
311
|
all_linear = modules == "all-linear"
|
|
309
312
|
targets = () if all_linear else tuple(modules) if isinstance(modules, list) else ()
|
|
310
|
-
groups: dict[str, dict[str,
|
|
313
|
+
groups: dict[str, dict[str, tuple[str, tuple[int, ...]]]] = {}
|
|
311
314
|
evidence: set[str] = set()
|
|
312
|
-
for module_path, factor,
|
|
315
|
+
for module_path, factor, key, shape in tensors:
|
|
313
316
|
if _is_fused_rung(module_path, fused_rungs):
|
|
314
317
|
continue
|
|
315
318
|
matched = tuple(target for target in targets if _anchored_suffix_match(module_path, target))
|
|
316
319
|
if not all_linear and not matched:
|
|
317
320
|
continue
|
|
318
321
|
evidence.update(matched)
|
|
319
|
-
groups.setdefault(module_path, {})
|
|
322
|
+
groups.setdefault(module_path, {})[factor] = (key, shape)
|
|
320
323
|
if not groups or (not all_linear and evidence != set(targets)):
|
|
321
324
|
return False
|
|
322
325
|
|
|
323
326
|
declared = declared_lora_ranks(config)
|
|
324
|
-
for module_path,
|
|
325
|
-
if
|
|
327
|
+
for module_path, factors in groups.items():
|
|
328
|
+
if _rank_for_module(module_path, declared) is None:
|
|
326
329
|
return False
|
|
327
|
-
factors = next(iter(namespaces.values()))
|
|
328
330
|
if set(factors) != {"A", "B"}:
|
|
329
331
|
return False
|
|
330
332
|
for key, shape in factors.values():
|
|
@@ -140,6 +140,11 @@ def load_environment(**kwargs) -> MyEnv:
|
|
|
140
140
|
For tool use, dialogue, or games, subclass `EnvironmentMultiTurn` instead and drive the
|
|
141
141
|
conversation across turns. The reward is the same `RewardResult` contract either way.
|
|
142
142
|
|
|
143
|
+
If the environment class can return image-bearing user observations from `step_episode`, declare
|
|
144
|
+
`image_observations = True` on that class. This is a class capability, not a TOML setting: Flash uses
|
|
145
|
+
it to reject a text-only model or OPD teacher before model work. Set it only for environments that
|
|
146
|
+
can actually emit images. The capability does not by itself enable per-turn image rollout wiring.
|
|
147
|
+
|
|
143
148
|
### 2. Publish the environment
|
|
144
149
|
|
|
145
150
|
A managed run references a **published** environment by id — so push your folder first:
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"""bounded parsing and validation for managed image descriptors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import binascii
|
|
7
|
+
import io
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
import warnings
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
_EXIF_ORIENTATION_TAG = 274
|
|
17
|
+
_EXIF_TRANSPOSED_ORIENTATIONS = frozenset({5, 6, 7, 8})
|
|
18
|
+
_MIME_TO_FORMAT = {
|
|
19
|
+
"image/jpeg": "JPEG",
|
|
20
|
+
"image/png": "PNG",
|
|
21
|
+
"image/webp": "WEBP",
|
|
22
|
+
}
|
|
23
|
+
_FORMAT_TO_MIME = {image_format: mime for mime, image_format in _MIME_TO_FORMAT.items()}
|
|
24
|
+
_DATA_URI_RE = re.compile(r"\Adata:(image/[^;,]+);base64,(.*)\Z", re.DOTALL)
|
|
25
|
+
_MODE_BYTES_PER_PIXEL = {
|
|
26
|
+
"1": 1,
|
|
27
|
+
"L": 1,
|
|
28
|
+
"P": 1,
|
|
29
|
+
"I;16": 2,
|
|
30
|
+
"I;16B": 2,
|
|
31
|
+
"I;16L": 2,
|
|
32
|
+
"LA": 2,
|
|
33
|
+
"La": 2,
|
|
34
|
+
"RGB": 3,
|
|
35
|
+
"YCbCr": 3,
|
|
36
|
+
"LAB": 3,
|
|
37
|
+
"HSV": 3,
|
|
38
|
+
"RGBA": 4,
|
|
39
|
+
"RGBa": 4,
|
|
40
|
+
"CMYK": 4,
|
|
41
|
+
"I": 4,
|
|
42
|
+
"F": 4,
|
|
43
|
+
}
|
|
44
|
+
RGB_BYTES_PER_PIXEL = 3
|
|
45
|
+
# decoding one image costs its own buffer plus a transient RGB conversion, so the worst mode
|
|
46
|
+
# sets the bytes-per-pixel a pixel budget has to assume. exported because the per-image pixel cap
|
|
47
|
+
# is derived from it: a cap the decoded-memory guard would always reject is not a limit.
|
|
48
|
+
WORST_BYTES_PER_PIXEL = max(_MODE_BYTES_PER_PIXEL.values()) + 2 * RGB_BYTES_PER_PIXEL
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True)
|
|
52
|
+
class ImageDescriptorLimits:
|
|
53
|
+
max_images: int
|
|
54
|
+
max_source_bytes: int
|
|
55
|
+
max_total_source_bytes: int
|
|
56
|
+
max_width: int
|
|
57
|
+
max_height: int
|
|
58
|
+
max_pixels: int
|
|
59
|
+
max_total_decoded_bytes: int
|
|
60
|
+
max_data_uri_header_bytes: int
|
|
61
|
+
max_descriptor_bytes: int
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(frozen=True)
|
|
65
|
+
class ValidatedImageDescriptor:
|
|
66
|
+
data: bytes
|
|
67
|
+
data_uri: str
|
|
68
|
+
source_bytes: int
|
|
69
|
+
decoded_peak_bytes: int
|
|
70
|
+
width: int
|
|
71
|
+
height: int
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def pixels(self) -> int:
|
|
75
|
+
return self.width * self.height
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def descriptor_size(value: str) -> int:
|
|
79
|
+
return len(value.encode("utf-8"))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def descriptor(kind: str, value: str, *, max_descriptor_bytes: int) -> str:
|
|
83
|
+
encoded = json.dumps({"kind": kind, "value": value}, separators=(",", ":"), sort_keys=True)
|
|
84
|
+
size = descriptor_size(encoded)
|
|
85
|
+
if size > max_descriptor_bytes:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
f"encoded image descriptor exceeds the {max_descriptor_bytes}-byte limit ({size} bytes)"
|
|
88
|
+
)
|
|
89
|
+
return encoded
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def parse_descriptor(raw: str) -> tuple[str, str]:
|
|
93
|
+
try:
|
|
94
|
+
value = json.loads(raw)
|
|
95
|
+
except (TypeError, json.JSONDecodeError) as exc:
|
|
96
|
+
raise ValueError("invalid internal image descriptor") from exc
|
|
97
|
+
if not isinstance(value, dict) or set(value) != {"kind", "value"}:
|
|
98
|
+
raise ValueError("invalid internal image descriptor")
|
|
99
|
+
kind = value["kind"]
|
|
100
|
+
payload = value["value"]
|
|
101
|
+
if not isinstance(kind, str) or not isinstance(payload, str):
|
|
102
|
+
raise ValueError("invalid internal image descriptor")
|
|
103
|
+
return kind, payload
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def check_source_size(size: int, *, max_source_bytes: int) -> None:
|
|
107
|
+
if size > max_source_bytes:
|
|
108
|
+
raise ValueError(f"image source exceeds the {max_source_bytes}-byte limit ({size} bytes)")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def decode_data_uri(uri: str, limits: ImageDescriptorLimits) -> tuple[bytes, str]:
|
|
112
|
+
comma = uri.find(",")
|
|
113
|
+
header = uri if comma < 0 else uri[:comma]
|
|
114
|
+
if len(header.encode("utf-8")) > limits.max_data_uri_header_bytes:
|
|
115
|
+
raise ValueError(
|
|
116
|
+
f"image data URI header exceeds the {limits.max_data_uri_header_bytes}-byte limit"
|
|
117
|
+
)
|
|
118
|
+
match = _DATA_URI_RE.fullmatch(uri)
|
|
119
|
+
if match is None:
|
|
120
|
+
if not uri.startswith("data:"):
|
|
121
|
+
raise ValueError("image source must use a data URI")
|
|
122
|
+
if ";base64," not in uri:
|
|
123
|
+
raise ValueError("image data URI must use base64 encoding")
|
|
124
|
+
raise ValueError("image data URI must use the exact data:image/...;base64,... format")
|
|
125
|
+
mime, payload = match.groups()
|
|
126
|
+
expected_format = _MIME_TO_FORMAT.get(mime)
|
|
127
|
+
if expected_format is None:
|
|
128
|
+
raise ValueError(f"image data URI uses unsupported MIME type {mime!r}")
|
|
129
|
+
max_encoded_size = ((limits.max_source_bytes + 2) // 3) * 4
|
|
130
|
+
if len(payload) > max_encoded_size:
|
|
131
|
+
check_source_size(
|
|
132
|
+
limits.max_source_bytes + 1,
|
|
133
|
+
max_source_bytes=limits.max_source_bytes,
|
|
134
|
+
)
|
|
135
|
+
try:
|
|
136
|
+
data = base64.b64decode(payload, validate=True)
|
|
137
|
+
except (binascii.Error, ValueError) as exc:
|
|
138
|
+
raise ValueError("image data URI contains invalid base64 data") from exc
|
|
139
|
+
check_source_size(len(data), max_source_bytes=limits.max_source_bytes)
|
|
140
|
+
return data, expected_format
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def package_image_path(
|
|
144
|
+
value: str, package_root: Path | None, limits: ImageDescriptorLimits
|
|
145
|
+
) -> Path:
|
|
146
|
+
if package_root is None:
|
|
147
|
+
raise ValueError("relative image paths require an extracted environment package root")
|
|
148
|
+
candidate = Path(value)
|
|
149
|
+
if candidate.is_absolute():
|
|
150
|
+
raise ValueError("image paths must be relative to the environment package root")
|
|
151
|
+
root = package_root.resolve()
|
|
152
|
+
dataset_root = (root / "dataset").resolve()
|
|
153
|
+
resolved = (root / candidate).resolve()
|
|
154
|
+
if resolved != dataset_root and dataset_root not in resolved.parents:
|
|
155
|
+
raise ValueError("image paths must stay inside the environment package dataset/ directory")
|
|
156
|
+
if not resolved.is_file():
|
|
157
|
+
raise ValueError(f"image path does not exist: {value!r}")
|
|
158
|
+
check_source_size(resolved.stat().st_size, max_source_bytes=limits.max_source_bytes)
|
|
159
|
+
return resolved
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def validate_dimensions(width: int, height: int, limits: ImageDescriptorLimits) -> int:
|
|
163
|
+
if width <= 0 or height <= 0:
|
|
164
|
+
raise ValueError("image width and height must be positive")
|
|
165
|
+
if width > limits.max_width or height > limits.max_height:
|
|
166
|
+
raise ValueError(
|
|
167
|
+
f"image dimensions {width}x{height} exceed the "
|
|
168
|
+
f"{limits.max_width}x{limits.max_height} limit"
|
|
169
|
+
)
|
|
170
|
+
pixels = width * height
|
|
171
|
+
if pixels > limits.max_pixels:
|
|
172
|
+
raise ValueError(
|
|
173
|
+
f"image has {pixels} pixels, exceeding the {limits.max_pixels}-pixel limit"
|
|
174
|
+
)
|
|
175
|
+
return pixels
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _oriented_dimensions(image: Any, width: int, height: int) -> tuple[int, int]:
|
|
179
|
+
try:
|
|
180
|
+
orientation = image.getexif().get(_EXIF_ORIENTATION_TAG)
|
|
181
|
+
except (AttributeError, TypeError, ValueError, SyntaxError):
|
|
182
|
+
orientation = None
|
|
183
|
+
if orientation in _EXIF_TRANSPOSED_ORIENTATIONS:
|
|
184
|
+
return height, width
|
|
185
|
+
return width, height
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def inspect_image_metadata(
|
|
189
|
+
data: bytes,
|
|
190
|
+
limits: ImageDescriptorLimits,
|
|
191
|
+
*,
|
|
192
|
+
expected_format: str | None = None,
|
|
193
|
+
) -> tuple[int, int, int, str]:
|
|
194
|
+
try:
|
|
195
|
+
from PIL import Image
|
|
196
|
+
except ImportError as exc:
|
|
197
|
+
raise RuntimeError("Pillow is required for multimodal image training") from exc
|
|
198
|
+
try:
|
|
199
|
+
with warnings.catch_warnings():
|
|
200
|
+
warnings.simplefilter("error", Image.DecompressionBombWarning)
|
|
201
|
+
with Image.open(io.BytesIO(data)) as image:
|
|
202
|
+
image_format = str(image.format or "").upper()
|
|
203
|
+
if image_format not in _FORMAT_TO_MIME:
|
|
204
|
+
raise ValueError("image source must be a static PNG, JPEG, or WebP image")
|
|
205
|
+
if expected_format is not None and image_format != expected_format:
|
|
206
|
+
raise ValueError(
|
|
207
|
+
f"image data URI MIME type does not match its {image_format} format"
|
|
208
|
+
)
|
|
209
|
+
if getattr(image, "n_frames", 1) != 1:
|
|
210
|
+
raise ValueError("image source must be a static single-frame image")
|
|
211
|
+
stored_width, stored_height = image.size
|
|
212
|
+
pixels = validate_dimensions(stored_width, stored_height, limits)
|
|
213
|
+
decoded_peak_bytes = pixels * (
|
|
214
|
+
_MODE_BYTES_PER_PIXEL.get(image.mode, 4) + 2 * RGB_BYTES_PER_PIXEL
|
|
215
|
+
)
|
|
216
|
+
image.verify()
|
|
217
|
+
with Image.open(io.BytesIO(data)) as orientation_probe:
|
|
218
|
+
width, height = _oriented_dimensions(
|
|
219
|
+
orientation_probe,
|
|
220
|
+
stored_width,
|
|
221
|
+
stored_height,
|
|
222
|
+
)
|
|
223
|
+
validate_dimensions(width, height, limits)
|
|
224
|
+
return decoded_peak_bytes, width, height, image_format
|
|
225
|
+
except ValueError:
|
|
226
|
+
raise
|
|
227
|
+
except Exception as exc:
|
|
228
|
+
raise ValueError("image source is not a valid image") from exc
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def inspect_image_bytes(data: bytes, limits: ImageDescriptorLimits) -> tuple[int, int, int]:
|
|
232
|
+
decoded_peak_bytes, width, height, _image_format = inspect_image_metadata(data, limits)
|
|
233
|
+
return decoded_peak_bytes, width, height
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def canonical_data_uri(data: bytes, image_format: str) -> str:
|
|
237
|
+
media_type = _FORMAT_TO_MIME.get(image_format)
|
|
238
|
+
if media_type is None:
|
|
239
|
+
raise ValueError("image source must be a static PNG, JPEG, or WebP image")
|
|
240
|
+
return f"data:{media_type};base64,{base64.b64encode(data).decode('ascii')}"
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def descriptor_source_size(
|
|
244
|
+
encoded: str,
|
|
245
|
+
package_root: str | Path | None,
|
|
246
|
+
limits: ImageDescriptorLimits,
|
|
247
|
+
) -> int:
|
|
248
|
+
kind, value = parse_descriptor(encoded)
|
|
249
|
+
if kind == "bytes":
|
|
250
|
+
return len(base64.b64decode(value, validate=True))
|
|
251
|
+
if kind == "data_uri":
|
|
252
|
+
return len(decode_data_uri(value, limits)[0])
|
|
253
|
+
if kind == "path":
|
|
254
|
+
root = Path(package_root) if package_root else None
|
|
255
|
+
return package_image_path(value, root, limits).stat().st_size
|
|
256
|
+
raise ValueError("invalid internal image descriptor kind")
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def read_descriptor_source(
|
|
260
|
+
encoded: str,
|
|
261
|
+
package_root: str | Path | None,
|
|
262
|
+
limits: ImageDescriptorLimits,
|
|
263
|
+
) -> bytes:
|
|
264
|
+
kind, value = parse_descriptor(encoded)
|
|
265
|
+
if kind == "bytes":
|
|
266
|
+
try:
|
|
267
|
+
data = base64.b64decode(value, validate=True)
|
|
268
|
+
except binascii.Error as exc:
|
|
269
|
+
raise ValueError("invalid internal byte image descriptor") from exc
|
|
270
|
+
elif kind == "data_uri":
|
|
271
|
+
data = decode_data_uri(value, limits)[0]
|
|
272
|
+
elif kind == "path":
|
|
273
|
+
root = Path(package_root) if package_root else None
|
|
274
|
+
data = package_image_path(value, root, limits).read_bytes()
|
|
275
|
+
else:
|
|
276
|
+
raise ValueError("invalid internal image descriptor kind")
|
|
277
|
+
check_source_size(len(data), max_source_bytes=limits.max_source_bytes)
|
|
278
|
+
return data
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def validate_image_descriptor_data(
|
|
282
|
+
encoded: str,
|
|
283
|
+
data: bytes,
|
|
284
|
+
limits: ImageDescriptorLimits,
|
|
285
|
+
*,
|
|
286
|
+
decode_pixels: bool,
|
|
287
|
+
pixel_decoder: Callable[[bytes], None],
|
|
288
|
+
) -> ValidatedImageDescriptor:
|
|
289
|
+
kind, value = parse_descriptor(encoded)
|
|
290
|
+
expected_format = decode_data_uri(value, limits)[1] if kind == "data_uri" else None
|
|
291
|
+
decoded_peak_bytes, width, height, image_format = inspect_image_metadata(
|
|
292
|
+
data,
|
|
293
|
+
limits,
|
|
294
|
+
expected_format=expected_format,
|
|
295
|
+
)
|
|
296
|
+
if decode_pixels:
|
|
297
|
+
pixel_decoder(data)
|
|
298
|
+
return ValidatedImageDescriptor(
|
|
299
|
+
data=data,
|
|
300
|
+
data_uri=canonical_data_uri(data, image_format),
|
|
301
|
+
source_bytes=len(data),
|
|
302
|
+
decoded_peak_bytes=decoded_peak_bytes,
|
|
303
|
+
width=width,
|
|
304
|
+
height=height,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def validate_image_descriptor(
|
|
309
|
+
encoded: str,
|
|
310
|
+
package_root: str | Path | None,
|
|
311
|
+
limits: ImageDescriptorLimits,
|
|
312
|
+
*,
|
|
313
|
+
decode_pixels: bool,
|
|
314
|
+
pixel_decoder: Callable[[bytes], None],
|
|
315
|
+
) -> ValidatedImageDescriptor:
|
|
316
|
+
data = read_descriptor_source(encoded, package_root, limits)
|
|
317
|
+
return validate_image_descriptor_data(
|
|
318
|
+
encoded,
|
|
319
|
+
data,
|
|
320
|
+
limits,
|
|
321
|
+
decode_pixels=decode_pixels,
|
|
322
|
+
pixel_decoder=pixel_decoder,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def validate_image_descriptors(
|
|
327
|
+
descriptors: list[str] | tuple[str, ...],
|
|
328
|
+
package_root: str | Path | None,
|
|
329
|
+
limits: ImageDescriptorLimits,
|
|
330
|
+
*,
|
|
331
|
+
pixel_decoder: Callable[[bytes], None],
|
|
332
|
+
) -> list[ValidatedImageDescriptor]:
|
|
333
|
+
if len(descriptors) > limits.max_images:
|
|
334
|
+
raise ValueError(
|
|
335
|
+
f"example contains {len(descriptors)} images, exceeding the "
|
|
336
|
+
f"{limits.max_images}-image limit"
|
|
337
|
+
)
|
|
338
|
+
validated: list[ValidatedImageDescriptor] = []
|
|
339
|
+
source_bytes = 0
|
|
340
|
+
prior_pixels = 0
|
|
341
|
+
for encoded in descriptors:
|
|
342
|
+
item = validate_image_descriptor(
|
|
343
|
+
encoded,
|
|
344
|
+
package_root,
|
|
345
|
+
limits,
|
|
346
|
+
decode_pixels=False,
|
|
347
|
+
pixel_decoder=pixel_decoder,
|
|
348
|
+
)
|
|
349
|
+
source_bytes += item.source_bytes
|
|
350
|
+
if source_bytes > limits.max_total_source_bytes:
|
|
351
|
+
raise ValueError(
|
|
352
|
+
f"example image sources exceed the {limits.max_total_source_bytes}-byte limit"
|
|
353
|
+
)
|
|
354
|
+
decoded_bytes = RGB_BYTES_PER_PIXEL * prior_pixels + item.decoded_peak_bytes
|
|
355
|
+
if decoded_bytes > limits.max_total_decoded_bytes:
|
|
356
|
+
raise ValueError(
|
|
357
|
+
f"example decoded images exceed the {limits.max_total_decoded_bytes}-byte limit"
|
|
358
|
+
)
|
|
359
|
+
prior_pixels += item.pixels
|
|
360
|
+
validated.append(item)
|
|
361
|
+
for item in validated:
|
|
362
|
+
pixel_decoder(item.data)
|
|
363
|
+
return validated
|