freesolo-flash-dev 1.0.85__tar.gz → 1.0.87__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.0.85 → freesolo_flash_dev-1.0.87}/.env.example +34 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/Dockerfile +13 -10
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/SELF_HOSTING.md +33 -0
- freesolo_flash_dev-1.0.87/deploy/infisical/Dockerfile +46 -0
- freesolo_flash_dev-1.0.87/deploy/infisical/README.md +73 -0
- freesolo_flash_dev-1.0.87/deploy/infisical/entrypoint.sh +76 -0
- freesolo_flash_dev-1.0.87/flash/_logging.py +100 -0
- freesolo_flash_dev-1.0.87/flash/_paths.py +37 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/TRAINING.md +3 -2
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/__init__.py +0 -4
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/env_setup.py +2 -1
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/render.py +1 -4
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/client/config.py +7 -2
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/recipe.py +15 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/opd_train.py +42 -2
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/perf/__init__.py +4 -9
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/multimodal.py +7 -118
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_worker.py +12 -22
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/jobs/__init__.py +3 -8
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/jobs.py +2 -11
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/train/endpoints.py +6 -23
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/runner/__init__.py +2 -1
- freesolo_flash_dev-1.0.87/flash/server/__main__.py +64 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/db.py +27 -3
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/teacher_broker.py +1 -1
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_render_coverage.py +2 -3
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_render_theme.py +2 -3
- freesolo_flash_dev-1.0.87/tests/test_config_env_vars.py +348 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_flash_worker.py +11 -16
- freesolo_flash_dev-1.0.87/tests/test_infisical_overlay.py +239 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_lambda_runner.py +0 -3
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_multimodal_training.py +13 -121
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_opd.py +8 -3
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_opd_train.py +99 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_parasail_teacher.py +15 -4
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_teacher_broker.py +17 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_worker_stack.py +8 -3
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/uv.lock +1 -1
- freesolo_flash_dev-1.0.85/flash/_logging.py +0 -37
- freesolo_flash_dev-1.0.85/flash/_update_check.py +0 -188
- freesolo_flash_dev-1.0.85/flash/server/__main__.py +0 -20
- freesolo_flash_dev-1.0.85/infisical-entrypoint.sh +0 -45
- freesolo_flash_dev-1.0.85/tests/test_update_check.py +0 -344
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/NOTICE +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/README.md +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/catalog.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/commands.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/env_eval.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/env_test.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/traces.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cli/training_doc.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/multiturn_reward_scoring.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/backend_common.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/grpo_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/grpo_plugin.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/multiturn_glue.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/opd.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/opd_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/opd_plugin.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/opd_structured.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/rl.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/rl_train.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/sft_train.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/teacher_encoding.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/opd_limits.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/opd_validation.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/providers/weight_cache_preload.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/projects.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/spec.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/flash/thinking.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_async_uploads.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_evaluations.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_rl_train.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_sft_train.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.85 → freesolo_flash_dev-1.0.87}/tests/test_worker_thinking.py +0 -0
|
@@ -66,6 +66,34 @@ FREESOLO_INTERNAL_KEY=
|
|
|
66
66
|
# accepted unverified. Single tenant - see SELF_HOSTING.md before enabling.
|
|
67
67
|
# FLASH_STANDALONE=1
|
|
68
68
|
|
|
69
|
+
# --- optional: deployment topology ---
|
|
70
|
+
# Where Flash keeps its local state: the saved login, the SQLite database, run records, and
|
|
71
|
+
# results. Defaults to ~/.flash (= /root/.flash for the container's default user, which is the
|
|
72
|
+
# path the Dockerfile declares as a VOLUME). Set this for a rootless container, a Kubernetes
|
|
73
|
+
# PVC, a read-only home directory, or a systemd unit with ProtectHome. Everything moves
|
|
74
|
+
# together, so point it at ONE durable location and mount a volume there.
|
|
75
|
+
# FLASH_DATA_DIR=/var/lib/flash
|
|
76
|
+
# Log verbosity for `flash-server`: DEBUG, INFO, WARNING, ERROR, CRITICAL. The server defaults
|
|
77
|
+
# to INFO -- provider resolution, capability revocation, reaper startup, and degraded-config
|
|
78
|
+
# warnings are all reported at INFO/WARNING. An unrecognized value falls back to the default
|
|
79
|
+
# rather than blocking startup.
|
|
80
|
+
# FLASH_LOG_LEVEL=INFO
|
|
81
|
+
# `text` (default) or `json`. JSON emits one object per line for a structured log sink. The
|
|
82
|
+
# same information is logged either way; only the punctuation differs.
|
|
83
|
+
# FLASH_LOG_FORMAT=text
|
|
84
|
+
# Bind address for `flash-server`. Defaults to 127.0.0.1; the container image passes 0.0.0.0
|
|
85
|
+
# explicitly. The --host and --port flags win over both of these.
|
|
86
|
+
# FLASH_SERVER_HOST=127.0.0.1
|
|
87
|
+
# Port for `flash-server`, default 8080. Must be 1-65535: an unusable value stops startup
|
|
88
|
+
# rather than silently binding the default, since a plane listening on the wrong port looks
|
|
89
|
+
# healthy and is unreachable.
|
|
90
|
+
# FLASH_SERVER_PORT=8080
|
|
91
|
+
# How long (seconds) to wait for a SQLite lock held by another writer, default 30. Raise it on
|
|
92
|
+
# networked storage, where a lock can be held far longer than on a local volume. This changes
|
|
93
|
+
# only patience: journal mode, synchronous, and foreign keys are correctness settings and are
|
|
94
|
+
# deliberately not configurable.
|
|
95
|
+
# FLASH_SQLITE_BUSY_TIMEOUT_SECONDS=30
|
|
96
|
+
|
|
69
97
|
# --- optional ---
|
|
70
98
|
# Server token for the environment repository. Without it, environments hosted in a
|
|
71
99
|
# private GitHub repo cannot be fetched; environments in public GitHub repos still work,
|
|
@@ -94,3 +122,9 @@ FLASH_CONTROL_PANEL_URL=https://flash.example.com
|
|
|
94
122
|
# URL here does not get you past the guard, it just produces the same error. Set it to
|
|
95
123
|
# YOUR serving deployment; the managed plane gets the hosted URL from the code default.
|
|
96
124
|
# FREESOLO_SERVING_URL=https://serving.example.internal
|
|
125
|
+
# Worker container image. Defaults to the published ghcr.io/freesolo-co/flash-worker tags
|
|
126
|
+
# (per-GPU-arch kernel-cache variants, falling back to the base :cu128). Point it at your
|
|
127
|
+
# own build to run a private worker; the CUDA driver floor still comes from the GPU class.
|
|
128
|
+
# FLASH_WORKER_IMAGE=ghcr.io/your-org/flash-worker:cu128
|
|
129
|
+
# Provider-side registry-credential id, required only when the image above is private.
|
|
130
|
+
# FLASH_WORKER_IMAGE_REGISTRY_AUTH=
|
|
@@ -5,9 +5,14 @@
|
|
|
5
5
|
# -e RUNPOD_API_KEY=... -e HF_TOKEN=... \
|
|
6
6
|
# -v flash-state:/root/.flash flash-control-plane
|
|
7
7
|
#
|
|
8
|
-
# All persistent state (key DB, run records, results) lives under ~/.flash (
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# All persistent state (key DB, run records, results) lives under ~/.flash (= /root/.flash for
|
|
9
|
+
# the default root user) — mount a volume there. Run exactly ONE container instance per state
|
|
10
|
+
# volume (state is local files + SQLite; no horizontal scaling).
|
|
11
|
+
#
|
|
12
|
+
# FLASH_DATA_DIR moves that root. The VOLUME below names the DEFAULT path, and Docker cannot
|
|
13
|
+
# declare a volume at a path chosen at runtime, so a container that sets FLASH_DATA_DIR must
|
|
14
|
+
# also mount its own volume at the new location — otherwise state lands on the container's
|
|
15
|
+
# writable layer and disappears when the container is replaced.
|
|
11
16
|
|
|
12
17
|
FROM python:3.12-slim
|
|
13
18
|
|
|
@@ -15,10 +20,7 @@ WORKDIR /app
|
|
|
15
20
|
COPY . .
|
|
16
21
|
RUN apt-get update \
|
|
17
22
|
&& apt-get install -y --no-install-recommends ca-certificates git curl \
|
|
18
|
-
&&
|
|
19
|
-
&& apt-get update && apt-get install -y --no-install-recommends infisical \
|
|
20
|
-
&& rm -rf /var/lib/apt/lists/* \
|
|
21
|
-
&& chmod +x /app/infisical-entrypoint.sh
|
|
23
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
22
24
|
RUN pip install --no-cache-dir ".[server]"
|
|
23
25
|
|
|
24
26
|
VOLUME /root/.flash
|
|
@@ -31,7 +33,8 @@ EXPOSE 8080
|
|
|
31
33
|
# bake-kernel-cache.yml so the -smXX tags don't ship stale deps (the worker-image build posts a
|
|
32
34
|
# reminder).
|
|
33
35
|
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
|
|
36
|
+
# Secrets come from the container environment (-e, --env-file, or your orchestrator's secret
|
|
37
|
+
# store), so this image needs no secret-manager tooling baked in. Pulling secrets from a manager
|
|
38
|
+
# at container start is an opt-in overlay that wraps this image's entrypoint and inherits the CMD
|
|
39
|
+
# below -- see deploy/infisical/ for a working example.
|
|
37
40
|
CMD ["python", "-m", "flash.server", "--host", "0.0.0.0", "--port", "8080"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.87
|
|
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
|
|
@@ -70,6 +70,39 @@ max_examples = 1000
|
|
|
70
70
|
file, load it: `set -a && . ./.env && set +a && flash-server`, or
|
|
71
71
|
`docker run --env-file .env ...`. Copy `.env.example` to start from a documented template.
|
|
72
72
|
|
|
73
|
+
The process environment is the only contract, so a Kubernetes Secret, systemd
|
|
74
|
+
`EnvironmentFile`, or any orchestrator's secret store works as-is. To pull secrets from a
|
|
75
|
+
secret manager at container start instead, wrap the image's entrypoint; `deploy/infisical/`
|
|
76
|
+
is a working example you can copy for another provider.
|
|
77
|
+
|
|
78
|
+
### The state directory
|
|
79
|
+
|
|
80
|
+
Everything the plane persists locally - the SQLite database of keys and run ownership, run
|
|
81
|
+
records, results, and the CLI's saved login - lives under one root, `~/.flash` by default
|
|
82
|
+
(`/root/.flash` in the container). Set `FLASH_DATA_DIR` to move it somewhere a rootless
|
|
83
|
+
container, a mounted PVC, or a `ProtectHome` systemd unit can actually write:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
FLASH_DATA_DIR=/var/lib/flash
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Everything moves together, so back up or mount that one directory. In Docker, setting
|
|
90
|
+
`FLASH_DATA_DIR` also means mounting your own volume at the new path - the image's `VOLUME`
|
|
91
|
+
declaration names the default location, and state written anywhere else lands on the
|
|
92
|
+
container's writable layer and is lost when the container is replaced.
|
|
93
|
+
|
|
94
|
+
Run exactly **one** instance per state directory. State is local files plus SQLite; there is
|
|
95
|
+
no horizontal scaling. On networked storage, where a lock can be held far longer than on a
|
|
96
|
+
local disk, raise `FLASH_SQLITE_BUSY_TIMEOUT_SECONDS` (default 30).
|
|
97
|
+
|
|
98
|
+
### Logs
|
|
99
|
+
|
|
100
|
+
`flash-server` logs at INFO. Provider resolution, capability revocation, reaper startup, and
|
|
101
|
+
degraded-configuration warnings are reported there and nowhere else, so that is the first
|
|
102
|
+
place to look when the plane misbehaves. `FLASH_LOG_LEVEL` turns it up (`DEBUG`) or down
|
|
103
|
+
(`WARNING`), and `FLASH_LOG_FORMAT=json` emits one JSON object per line for a structured log
|
|
104
|
+
sink.
|
|
105
|
+
|
|
73
106
|
## Environments
|
|
74
107
|
|
|
75
108
|
An environment is the Python package defining your task - dataset, rollout, reward. Point
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# OPT-IN Infisical overlay for the Flash control plane.
|
|
2
|
+
#
|
|
3
|
+
# Flash itself needs nothing from Infisical: it reads secrets from its process environment,
|
|
4
|
+
# so the base image already works with `docker run --env-file`, a kubernetes Secret, or any
|
|
5
|
+
# orchestrator's secret store. This overlay is for deployments that pull secrets from
|
|
6
|
+
# Infisical at container start instead. See README.md in this directory.
|
|
7
|
+
#
|
|
8
|
+
# Build it against a published tag:
|
|
9
|
+
#
|
|
10
|
+
# docker build -f deploy/infisical/Dockerfile \
|
|
11
|
+
# --build-arg FLASH_IMAGE=ghcr.io/freesolo-co/freesolo-flash:main \
|
|
12
|
+
# -t flash-control-plane-infisical .
|
|
13
|
+
#
|
|
14
|
+
# ...or against an image you just built yourself:
|
|
15
|
+
#
|
|
16
|
+
# docker build -t flash-control-plane .
|
|
17
|
+
# docker build -f deploy/infisical/Dockerfile \
|
|
18
|
+
# --build-arg FLASH_IMAGE=flash-control-plane -t flash-control-plane-infisical .
|
|
19
|
+
#
|
|
20
|
+
# The build context is the repository root (that is where entrypoint.sh is copied from).
|
|
21
|
+
|
|
22
|
+
ARG FLASH_IMAGE=ghcr.io/freesolo-co/freesolo-flash:main
|
|
23
|
+
FROM ${FLASH_IMAGE}
|
|
24
|
+
|
|
25
|
+
# The Infisical CLI comes from the vendor's apt repo, and is deliberately NOT installed by the
|
|
26
|
+
# base image: the published artifact ships no vendor secret tooling and no vendor apt source.
|
|
27
|
+
# (The base image's `COPY . .` does carry this directory's inert shell script, but nothing in
|
|
28
|
+
# the base image ever executes it.)
|
|
29
|
+
RUN apt-get update \
|
|
30
|
+
&& apt-get install -y --no-install-recommends ca-certificates curl \
|
|
31
|
+
&& curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
|
|
32
|
+
&& apt-get update && apt-get install -y --no-install-recommends infisical \
|
|
33
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
34
|
+
|
|
35
|
+
COPY deploy/infisical/entrypoint.sh /usr/local/bin/flash-infisical-entrypoint
|
|
36
|
+
RUN chmod +x /usr/local/bin/flash-infisical-entrypoint
|
|
37
|
+
|
|
38
|
+
# No-op passthrough unless INFISICAL_CLIENT_ID is set, otherwise `infisical login`
|
|
39
|
+
# (universal-auth) then `infisical run` before the server.
|
|
40
|
+
ENTRYPOINT ["/usr/local/bin/flash-infisical-entrypoint"]
|
|
41
|
+
|
|
42
|
+
# CMD must be restated, and must stay in step with the base Dockerfile's CMD. Setting
|
|
43
|
+
# ENTRYPOINT in a DERIVED image resets the inherited CMD to null, so without this line the
|
|
44
|
+
# wrapper is handed no command at all and the container never starts the server. Do not
|
|
45
|
+
# "deduplicate" this by deleting it.
|
|
46
|
+
CMD ["python", "-m", "flash.server", "--host", "0.0.0.0", "--port", "8080"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Infisical secret injection (opt-in)
|
|
2
|
+
|
|
3
|
+
Flash reads its secrets from the **process environment**. That is the whole contract, and it is
|
|
4
|
+
all a deployment needs:
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
docker run -p 8080:8080 --env-file .env -v flash-state:/root/.flash \
|
|
8
|
+
ghcr.io/freesolo-co/freesolo-flash:main
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Kubernetes Secrets, systemd `EnvironmentFile`, Docker secrets mounted into env, and every
|
|
12
|
+
orchestrator secret store already produce that environment. **If that covers you, ignore this
|
|
13
|
+
directory** — the published image has no Infisical CLI in it and does not need one.
|
|
14
|
+
|
|
15
|
+
This overlay is for deployments that instead fetch secrets from [Infisical](https://infisical.com)
|
|
16
|
+
at container start.
|
|
17
|
+
|
|
18
|
+
## Using it
|
|
19
|
+
|
|
20
|
+
Build the overlay on top of a Flash image:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
docker build -f deploy/infisical/Dockerfile \
|
|
24
|
+
--build-arg FLASH_IMAGE=ghcr.io/freesolo-co/freesolo-flash:main \
|
|
25
|
+
-t flash-control-plane-infisical .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Run it with a universal-auth machine identity:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
docker run -p 8080:8080 -v flash-state:/root/.flash \
|
|
32
|
+
-e INFISICAL_CLIENT_ID=... \
|
|
33
|
+
-e INFISICAL_CLIENT_SECRET=... \
|
|
34
|
+
-e INFISICAL_PROJECT_ID=... \
|
|
35
|
+
-e INFISICAL_PATH=/flash \
|
|
36
|
+
flash-control-plane-infisical
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The wrapper logs in, then execs `infisical run -- <the base image's CMD>`, so the server sees the
|
|
40
|
+
injected secrets as ordinary environment variables. It changes nothing about how Flash itself
|
|
41
|
+
resolves configuration.
|
|
42
|
+
|
|
43
|
+
You can also skip the overlay build and mount the script into the base image, provided the
|
|
44
|
+
`infisical` binary is available inside the container.
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
| Variable | Required | Default | Purpose |
|
|
49
|
+
| ------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `INFISICAL_CLIENT_ID` | yes | unset | Universal-auth machine identity. **Unset makes the wrapper a no-op passthrough**, so the container behaves exactly like the base image. |
|
|
51
|
+
| `INFISICAL_CLIENT_SECRET` | yes | unset | Machine identity secret. |
|
|
52
|
+
| `INFISICAL_PROJECT_ID` | yes | unset | Infisical project (workspace) id. |
|
|
53
|
+
| `INFISICAL_PATH` | yes | unset | Secret folder path for this service, e.g. `/flash`. |
|
|
54
|
+
| `INFISICAL_ENV` | no | `prod` | Environment slug. **A dev deployment that omits this loads production secrets.** |
|
|
55
|
+
| `INFISICAL_KEEP` | no | empty | Space-separated variable _names_ whose existing container values must win over the injected ones. `infisical run` overrides existing env, so these are re-applied after injection. Use it for values that are a property of where the container runs, like a `FREESOLO_BASE_URL` pointing at a service on the same Docker network. |
|
|
56
|
+
|
|
57
|
+
`INFISICAL_TOKEN` is minted by the wrapper at startup. Do not set it yourself.
|
|
58
|
+
|
|
59
|
+
A name listed in `INFISICAL_KEEP` that the container has **not** set is skipped, so the vault's
|
|
60
|
+
value survives — a typo there costs you an override, not a credential. Setting a name to an empty
|
|
61
|
+
string is treated as a deliberate choice and still wins over the vault. Entries must be shell
|
|
62
|
+
identifiers; anything else aborts startup rather than being evaluated.
|
|
63
|
+
|
|
64
|
+
## Failure behaviour
|
|
65
|
+
|
|
66
|
+
The wrapper runs under `set -eu`: a failed login or a missing `INFISICAL_PROJECT_ID` /
|
|
67
|
+
`INFISICAL_PATH` aborts container start rather than silently booting a control plane with no
|
|
68
|
+
credentials. Flash's own startup preflight would reject that state anyway, but failing at the
|
|
69
|
+
wrapper keeps the cause in the first line of the container log.
|
|
70
|
+
|
|
71
|
+
Only `INFISICAL_CLIENT_ID` is checked for presence, because it is the switch. With it set and the
|
|
72
|
+
rest missing, you get a hard failure — which is the intended outcome, not a fallback to unset
|
|
73
|
+
secrets.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# OPT-IN: wraps the flash control-plane command with infisical secret injection.
|
|
3
|
+
#
|
|
4
|
+
# The published image does NOT use this. Flash reads secrets from its process environment,
|
|
5
|
+
# so `docker run -e ... / --env-file`, a kubernetes Secret, or any orchestrator's secret
|
|
6
|
+
# store works with no wrapper at all. This file exists for deployments that pull secrets
|
|
7
|
+
# from Infisical at container start; see deploy/infisical/README.md to opt in.
|
|
8
|
+
#
|
|
9
|
+
# fallback-safe: if INFISICAL_CLIENT_ID is unset this is a no-op passthrough and the
|
|
10
|
+
# container behaves exactly as it does without the wrapper (reading its env_file / docker
|
|
11
|
+
# env). Once the bootstrap machine-identity creds are present, secrets are pulled from
|
|
12
|
+
# infisical at startup.
|
|
13
|
+
#
|
|
14
|
+
# expected env:
|
|
15
|
+
# INFISICAL_CLIENT_ID / INFISICAL_CLIENT_SECRET universal-auth machine identity creds
|
|
16
|
+
# INFISICAL_PROJECT_ID the infisical project (workspace) id
|
|
17
|
+
# INFISICAL_ENV env slug (prod | dev); default prod
|
|
18
|
+
# INFISICAL_PATH folder path for this service (e.g. /flash)
|
|
19
|
+
# INFISICAL_KEEP space-separated var names that must WIN over
|
|
20
|
+
# infisical (docker-network overrides). infisical
|
|
21
|
+
# run overrides existing env, so we re-apply these
|
|
22
|
+
# AFTER injection via `env K=V`.
|
|
23
|
+
set -eu
|
|
24
|
+
|
|
25
|
+
# `exec "$@"` with ZERO arguments is a no-op that FALLS THROUGH to the injection path below,
|
|
26
|
+
# where `set -u` then blames INFISICAL_CLIENT_ID for what is really a missing command. Setting
|
|
27
|
+
# ENTRYPOINT in a derived image resets the inherited CMD to null, so an overlay that forgets to
|
|
28
|
+
# restate CMD lands here. Fail with the actual cause instead.
|
|
29
|
+
if [ "$#" -eq 0 ]; then
|
|
30
|
+
echo "flash infisical entrypoint: no command given (the image's CMD is empty)" >&2
|
|
31
|
+
exit 2
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if [ -z "${INFISICAL_CLIENT_ID:-}" ]; then
|
|
35
|
+
exec "$@"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
INFISICAL_TOKEN="$(infisical login --method=universal-auth \
|
|
39
|
+
--client-id="$INFISICAL_CLIENT_ID" \
|
|
40
|
+
--client-secret="$INFISICAL_CLIENT_SECRET" \
|
|
41
|
+
--silent --plain)"
|
|
42
|
+
export INFISICAL_TOKEN
|
|
43
|
+
|
|
44
|
+
# Re-apply the docker-network overrides AFTER infisical injection so they win. infisical
|
|
45
|
+
# run overrides existing env, so we hand each KEEP var to `env` as its own quoted `K=V`
|
|
46
|
+
# argument — values that contain spaces or shell metacharacters survive intact. (Building
|
|
47
|
+
# an unquoted string and word-splitting it would corrupt such values, and a leading space
|
|
48
|
+
# would make `env` choke.) INFISICAL_KEEP itself is a whitespace-separated list of variable
|
|
49
|
+
# NAMES, so splitting *it* is intentional.
|
|
50
|
+
# shellcheck disable=SC2086
|
|
51
|
+
for k in ${INFISICAL_KEEP:-}; do
|
|
52
|
+
# These names are expanded inside `eval` below, so refuse anything that is not a shell
|
|
53
|
+
# identifier instead of executing it.
|
|
54
|
+
case $k in
|
|
55
|
+
[!A-Za-z_]* | *[!A-Za-z0-9_]*)
|
|
56
|
+
echo "flash infisical entrypoint: INFISICAL_KEEP entry is not a variable name: $k" >&2
|
|
57
|
+
exit 2
|
|
58
|
+
;;
|
|
59
|
+
esac
|
|
60
|
+
# Only re-apply names the container actually SET. An unset name expands to nothing, and
|
|
61
|
+
# handing `env` a bare `K=` would overwrite the injected secret with an empty string --
|
|
62
|
+
# so a typo'd or absent KEEP entry would silently WIPE a credential rather than leave the
|
|
63
|
+
# vault's value alone. `${K+set}` distinguishes unset from set-but-empty, so an explicitly
|
|
64
|
+
# empty container value still wins (that is a deliberate choice by whoever wrote it).
|
|
65
|
+
eval "keep_is_set=\${$k+set}"
|
|
66
|
+
[ "${keep_is_set:-}" = set ] || continue
|
|
67
|
+
set -- "$k=$(eval "printf '%s' \"\${$k}\"")" "$@"
|
|
68
|
+
done
|
|
69
|
+
unset keep_is_set
|
|
70
|
+
|
|
71
|
+
exec infisical run \
|
|
72
|
+
--projectId "$INFISICAL_PROJECT_ID" \
|
|
73
|
+
--env "${INFISICAL_ENV:-prod}" \
|
|
74
|
+
--path "$INFISICAL_PATH" \
|
|
75
|
+
--silent \
|
|
76
|
+
-- env "$@"
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Package logging helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
_ROOT_NAME = "flash"
|
|
10
|
+
|
|
11
|
+
LOG_LEVEL_ENV = "FLASH_LOG_LEVEL"
|
|
12
|
+
LOG_FORMAT_ENV = "FLASH_LOG_FORMAT"
|
|
13
|
+
|
|
14
|
+
_TEXT_FORMAT = "%(levelname)s %(name)s: %(message)s"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _JsonFormatter(logging.Formatter):
|
|
18
|
+
"""One JSON object per line, for deployments that ship logs to a structured sink.
|
|
19
|
+
|
|
20
|
+
This formats the SAME record the text formatter would, through the same
|
|
21
|
+
``record.getMessage()`` path. Nothing is added to the payload that the text line does not
|
|
22
|
+
already carry, so choosing a format cannot change what ends up in the log -- only how it is
|
|
23
|
+
punctuated. Anything a caller must not log stays un-logged in both formats.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
27
|
+
payload = {
|
|
28
|
+
"level": record.levelname,
|
|
29
|
+
"logger": record.name,
|
|
30
|
+
"message": record.getMessage(),
|
|
31
|
+
}
|
|
32
|
+
if record.exc_info:
|
|
33
|
+
payload["exception"] = self.formatException(record.exc_info)
|
|
34
|
+
return json.dumps(payload, default=str)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _resolve_level(verbosity: int, level: int | None, default_level: int) -> int:
|
|
38
|
+
"""Explicit level wins, then -v flags, then FLASH_LOG_LEVEL, then the caller's default.
|
|
39
|
+
|
|
40
|
+
A caller that passed an explicit level or counted -v flags has said what it wants for this
|
|
41
|
+
invocation, so the environment does not override it. ``default_level`` is the opposite: it
|
|
42
|
+
is what the entrypoint would have used anyway, so an operator's FLASH_LOG_LEVEL beats it.
|
|
43
|
+
That ordering is what makes the variable useful -- the server defaults to INFO and can still
|
|
44
|
+
be turned down to WARNING or up to DEBUG without a code change.
|
|
45
|
+
"""
|
|
46
|
+
if level is not None:
|
|
47
|
+
return level
|
|
48
|
+
if verbosity:
|
|
49
|
+
return {1: logging.INFO}.get(verbosity, logging.DEBUG)
|
|
50
|
+
configured = os.environ.get(LOG_LEVEL_ENV, "").strip().upper()
|
|
51
|
+
if configured:
|
|
52
|
+
# getLevelName maps a known name to its int; an unknown name comes back as the string
|
|
53
|
+
# "Level FOO", which is not an int -- so a typo falls back rather than raising at startup.
|
|
54
|
+
# A log level is not worth refusing to boot over.
|
|
55
|
+
resolved = logging.getLevelName(configured)
|
|
56
|
+
if isinstance(resolved, int):
|
|
57
|
+
return resolved
|
|
58
|
+
return default_level
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _resolve_formatter() -> logging.Formatter:
|
|
62
|
+
if os.environ.get(LOG_FORMAT_ENV, "").strip().lower() == "json":
|
|
63
|
+
return _JsonFormatter()
|
|
64
|
+
return logging.Formatter(_TEXT_FORMAT)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# NullHandler: keep library import silent; app opts in via configure_logging.
|
|
68
|
+
_root = logging.getLogger(_ROOT_NAME)
|
|
69
|
+
if not any(isinstance(h, logging.NullHandler) for h in _root.handlers):
|
|
70
|
+
_root.addHandler(logging.NullHandler())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_logger(name: str | None = None) -> logging.Logger:
|
|
74
|
+
"""Return a logger under the ``flash`` namespace (e.g. ``get_logger(__name__)``)."""
|
|
75
|
+
if not name or name == _ROOT_NAME:
|
|
76
|
+
return logging.getLogger(_ROOT_NAME)
|
|
77
|
+
if name.startswith(_ROOT_NAME + "."):
|
|
78
|
+
return logging.getLogger(name)
|
|
79
|
+
return logging.getLogger(f"{_ROOT_NAME}.{name}")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def configure_logging(
|
|
83
|
+
verbosity: int = 0, level: int | None = None, default_level: int = logging.WARNING
|
|
84
|
+
) -> None:
|
|
85
|
+
"""Attach a console handler to the ``flash`` logger and set its level.
|
|
86
|
+
|
|
87
|
+
``FLASH_LOG_LEVEL`` sets the level when the caller has not asked for a specific one, and
|
|
88
|
+
``FLASH_LOG_FORMAT=json`` switches the console handler to one JSON object per line.
|
|
89
|
+
"""
|
|
90
|
+
level = _resolve_level(verbosity, level, default_level)
|
|
91
|
+
|
|
92
|
+
logger = logging.getLogger(_ROOT_NAME)
|
|
93
|
+
logger.setLevel(level)
|
|
94
|
+
for h in [h for h in logger.handlers if getattr(h, "_flash_console", False)]:
|
|
95
|
+
logger.removeHandler(h)
|
|
96
|
+
handler = logging.StreamHandler()
|
|
97
|
+
handler.setLevel(level)
|
|
98
|
+
handler.setFormatter(_resolve_formatter())
|
|
99
|
+
handler._flash_console = True # type: ignore[attr-defined]
|
|
100
|
+
logger.addHandler(handler)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""The one place Flash decides where its local state lives.
|
|
2
|
+
|
|
3
|
+
Everything Flash persists on the machine it runs on -- the CLI's saved login, the control
|
|
4
|
+
plane's SQLite database, run records and results, and the RunPod SDK's resource registry --
|
|
5
|
+
hangs off a single root. ``FLASH_DATA_DIR`` moves that root; unset, it is ``~/.flash``, which
|
|
6
|
+
is where every one of those things already lived.
|
|
7
|
+
|
|
8
|
+
Why this module exists at all: four call sites used to spell ``~/.flash`` out for themselves.
|
|
9
|
+
Nothing kept them in agreement, so a deployment could only relocate state by editing Python in
|
|
10
|
+
four places and state could silently split if it edited three. Resolution is centralized here
|
|
11
|
+
so there is exactly one answer to "where does Flash keep its files".
|
|
12
|
+
|
|
13
|
+
The root is resolved per call rather than captured at import, because a process that sets the
|
|
14
|
+
variable after importing flash (tests, embedders) would otherwise get the old answer.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
DATA_DIR_ENV = "FLASH_DATA_DIR"
|
|
23
|
+
DEFAULT_DATA_DIR_NAME = ".flash"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def data_dir() -> Path:
|
|
27
|
+
"""The root under which Flash keeps its local state.
|
|
28
|
+
|
|
29
|
+
A relative ``FLASH_DATA_DIR`` is resolved against the current working directory, which makes
|
|
30
|
+
the path a process-lifetime-stable answer only if the process does not chdir. Absolute paths
|
|
31
|
+
are what a deployment should set; ``expanduser`` keeps ``~/...`` working for a human typing
|
|
32
|
+
it into a shell.
|
|
33
|
+
"""
|
|
34
|
+
configured = os.environ.get(DATA_DIR_ENV, "").strip()
|
|
35
|
+
if configured:
|
|
36
|
+
return Path(configured).expanduser()
|
|
37
|
+
return Path.home() / DEFAULT_DATA_DIR_NAME
|
|
@@ -850,7 +850,7 @@ with no reward to design. It supports `epochs` like SFT/GRPO and produces a LoRA
|
|
|
850
850
|
|
|
851
851
|
- **Pick the teacher with `[train] teacher_model`; the key stays managed.** The teacher defaults to
|
|
852
852
|
the managed **GLM 5.2** and is selectable from a fixed, managed allow-list:
|
|
853
|
-
`glm-5.2` (default), `kimi-k3`,
|
|
853
|
+
`glm-5.2` (default), `kimi-k3`, `qwen3.5-397b-a17b`, or `deepseek-v4-pro`. Every option is
|
|
854
854
|
a Parasail-hosted model reached through the control-plane broker, so there is nothing to export or
|
|
855
855
|
declare. An opd run submits like any other, and a `PARASAIL_API_KEY` in your shell is ignored.
|
|
856
856
|
Arbitrary bring-your-own teacher models or keys are not supported (the allow-list is curated to
|
|
@@ -886,7 +886,8 @@ max_examples = 2
|
|
|
886
886
|
lora_rank = 32
|
|
887
887
|
# teacher_model = "glm-5.2" # managed teacher to distil from; one of
|
|
888
888
|
# # glm-5.2 (default) | kimi-k3 |
|
|
889
|
-
# # qwen3.5-397b-a17b
|
|
889
|
+
# # qwen3.5-397b-a17b | deepseek-v4-pro
|
|
890
|
+
# # (key stays managed)
|
|
890
891
|
# kl_penalty_coef = 1.0 # reverse-KL scale
|
|
891
892
|
```
|
|
892
893
|
|
|
@@ -13,7 +13,6 @@ from typing import NoReturn
|
|
|
13
13
|
from flash import __version__
|
|
14
14
|
from flash._channel import CLI_NAME
|
|
15
15
|
from flash._logging import configure_logging
|
|
16
|
-
from flash._update_check import emit_update_notice, maybe_start_update_check
|
|
17
16
|
from flash.catalog import ALGORITHMS
|
|
18
17
|
from flash.cli import render
|
|
19
18
|
|
|
@@ -766,7 +765,6 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
766
765
|
args = parser.parse_args(argv)
|
|
767
766
|
configure_logging(verbosity=getattr(args, "verbose", 0))
|
|
768
767
|
debug = getattr(args, "debug", False)
|
|
769
|
-
update_check = maybe_start_update_check()
|
|
770
768
|
_warn_if_login_shadowed(args)
|
|
771
769
|
try:
|
|
772
770
|
return args.func(args)
|
|
@@ -798,5 +796,3 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
798
796
|
print(render.error(str(exc) or exc.__class__.__name__), file=sys.stderr)
|
|
799
797
|
print(render.arrow(f"run `{cmd}` for the full traceback"), file=sys.stderr)
|
|
800
798
|
return 1
|
|
801
|
-
finally:
|
|
802
|
-
emit_update_notice(update_check)
|
|
@@ -667,7 +667,8 @@ def cmd_env_setup(args) -> int:
|
|
|
667
667
|
f"{max_examples_line}"
|
|
668
668
|
"lora_rank = 32\n"
|
|
669
669
|
'# teacher_model = "glm-5.2" # teacher: glm-5.2 (default) | kimi-k3 |\n'
|
|
670
|
-
"# # qwen3.5-397b-a17b
|
|
670
|
+
"# # qwen3.5-397b-a17b | deepseek-v4-pro\n"
|
|
671
|
+
"# # (key stays managed)\n"
|
|
671
672
|
"# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
|
|
672
673
|
"# the cheapest fitting managed class, and artifacts live in a private environment-scoped repo.\n"
|
|
673
674
|
)
|
|
@@ -195,10 +195,7 @@ def _truecolor() -> bool:
|
|
|
195
195
|
|
|
196
196
|
|
|
197
197
|
def _theme() -> str:
|
|
198
|
-
"""Active theme: ``light`` or ``dark
|
|
199
|
-
forced = os.environ.get("FLASH_THEME", "").strip().lower()
|
|
200
|
-
if forced in {"light", "dark"}:
|
|
201
|
-
return forced
|
|
198
|
+
"""Active theme: ``light`` or ``dark``, inferred from ``COLORFGBG`` (the terminal's own signal)."""
|
|
202
199
|
fgbg = os.environ.get("COLORFGBG", "")
|
|
203
200
|
if fgbg:
|
|
204
201
|
try:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Client-side credential storage: Flash API key + control-plane URL.
|
|
2
2
|
|
|
3
|
-
Stored in
|
|
3
|
+
Stored in ``config.json`` (0600) under the Flash data dir, ``~/.flash`` unless
|
|
4
|
+
``FLASH_DATA_DIR`` says otherwise. ``FREESOLO_API_KEY`` / ``FLASH_API_URL`` override.
|
|
4
5
|
"""
|
|
5
6
|
|
|
6
7
|
from __future__ import annotations
|
|
@@ -10,6 +11,7 @@ from pathlib import Path
|
|
|
10
11
|
|
|
11
12
|
from .._channel import CHANNEL, CLI_NAME
|
|
12
13
|
from .._fileio import read_json_or_empty, secure_json_write
|
|
14
|
+
from .._paths import data_dir
|
|
13
15
|
|
|
14
16
|
PROD_API_URL = "https://flash.freesolo.co"
|
|
15
17
|
DEV_API_URL = "https://flash-dev.freesolo.co"
|
|
@@ -22,7 +24,10 @@ def default_api_url(channel: str = CHANNEL) -> str:
|
|
|
22
24
|
|
|
23
25
|
DEFAULT_API_URL = default_api_url()
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
# Resolved at import so the CLI reports one stable path for the life of a command: these appear
|
|
28
|
+
# in user-facing messages ("the login saved in ..."), and a value that changed between the read
|
|
29
|
+
# and the message would name a file the user was not told about.
|
|
30
|
+
CONFIG_DIR = data_dir()
|
|
26
31
|
CONFIG_PATH = CONFIG_DIR / "config.json"
|
|
27
32
|
|
|
28
33
|
|
|
@@ -59,6 +59,21 @@ TEACHER_MODELS: dict[str, TeacherModel] = {
|
|
|
59
59
|
),
|
|
60
60
|
),
|
|
61
61
|
),
|
|
62
|
+
"deepseek-v4-pro": TeacherModel(
|
|
63
|
+
alias="deepseek-v4-pro",
|
|
64
|
+
model_id="parasail-deepseek-v4-pro",
|
|
65
|
+
display_name="DeepSeek V4 Pro",
|
|
66
|
+
usd_per_1m=(1.74, 3.48),
|
|
67
|
+
tokenizer_repo="deepseek-ai/DeepSeek-V4-Pro",
|
|
68
|
+
tokenizer_revision="b5968e9190ef611bbf34a7229255be88a0e937c1",
|
|
69
|
+
tokenizer_kind="tokenizer_json",
|
|
70
|
+
tokenizer_files=(
|
|
71
|
+
(
|
|
72
|
+
"tokenizer.json",
|
|
73
|
+
"8f9f37ca37fdc4f5fd36d5cf4d3b0e8392edb4e894fd10cc0d70b4957c8633cf",
|
|
74
|
+
),
|
|
75
|
+
),
|
|
76
|
+
),
|
|
62
77
|
"qwen3.5-397b-a17b": TeacherModel(
|
|
63
78
|
alias="qwen3.5-397b-a17b",
|
|
64
79
|
model_id="parasail-qwen35-397b-a17b",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import contextlib
|
|
5
6
|
import copy
|
|
6
7
|
import hashlib
|
|
7
8
|
import http.client
|
|
@@ -1817,11 +1818,50 @@ def _opd_multimodal_parquet_features():
|
|
|
1817
1818
|
)
|
|
1818
1819
|
|
|
1819
1820
|
|
|
1821
|
+
# arrow expands every shared python reference into its own copy, and the opd row list is one
|
|
1822
|
+
# reference per prompt repeated across the whole horizon, so converting the rows in a single table
|
|
1823
|
+
# costs peak host ram proportional to horizon * prompts_per_step * prompt_bytes. that is the parent
|
|
1824
|
+
# worker's ram, not the gpu's, and the allocator sizes vram only -- a host-ram kill surfaces as a
|
|
1825
|
+
# generic child exit with oom:false. writing in fixed batches holds the peak flat instead
|
|
1826
|
+
# (measured: 24k rows of ~8k-token prompts, 6143 MB in one table vs 189 MB batched).
|
|
1827
|
+
_OPD_PARQUET_WRITE_BATCH_ROWS = 2000
|
|
1828
|
+
|
|
1829
|
+
|
|
1820
1830
|
def _write_opd_parquet(rows: list[dict], path: str) -> None:
|
|
1821
|
-
|
|
1831
|
+
import pyarrow as pa
|
|
1832
|
+
import pyarrow.parquet as pq
|
|
1822
1833
|
|
|
1834
|
+
if not rows:
|
|
1835
|
+
raise ValueError("refusing to write an empty OPD parquet")
|
|
1823
1836
|
features = _opd_multimodal_parquet_features() if any("images" in row for row in rows) else None
|
|
1824
|
-
|
|
1837
|
+
# pin one schema for every batch. multimodal takes it from the declared features exactly as the
|
|
1838
|
+
# single-table write did; text infers it from the first batch so a later batch cannot silently
|
|
1839
|
+
# infer a different type and be rejected mid-file.
|
|
1840
|
+
schema = (
|
|
1841
|
+
features.arrow_schema
|
|
1842
|
+
if features is not None
|
|
1843
|
+
else pa.Table.from_pylist(rows[:_OPD_PARQUET_WRITE_BATCH_ROWS]).schema
|
|
1844
|
+
)
|
|
1845
|
+
# write to a sibling temp file and rename only once every batch landed. closing a partially
|
|
1846
|
+
# written ParquetWriter still emits a valid footer, so failing in place would leave a READABLE
|
|
1847
|
+
# short file at `path` -- a truncated horizon that trains silently instead of raising.
|
|
1848
|
+
partial = f"{path}.partial"
|
|
1849
|
+
try:
|
|
1850
|
+
writer = pq.ParquetWriter(partial, schema)
|
|
1851
|
+
try:
|
|
1852
|
+
for start in range(0, len(rows), _OPD_PARQUET_WRITE_BATCH_ROWS):
|
|
1853
|
+
writer.write_table(
|
|
1854
|
+
pa.Table.from_pylist(
|
|
1855
|
+
rows[start : start + _OPD_PARQUET_WRITE_BATCH_ROWS], schema=schema
|
|
1856
|
+
)
|
|
1857
|
+
)
|
|
1858
|
+
finally:
|
|
1859
|
+
writer.close()
|
|
1860
|
+
os.replace(partial, path)
|
|
1861
|
+
except BaseException:
|
|
1862
|
+
with contextlib.suppress(OSError):
|
|
1863
|
+
os.remove(partial)
|
|
1864
|
+
raise
|
|
1825
1865
|
|
|
1826
1866
|
|
|
1827
1867
|
# the verl bridge stores the empty-alignment skip under its own internal key,
|