freesolo-flash-dev 1.0.45__tar.gz → 1.0.47__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.45 → freesolo_flash_dev-1.0.47}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/heartbeat.py +2 -2
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/opd_verl.py +17 -6
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/rl_verl.py +84 -16
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/sft_verl.py +12 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/verl_common.py +173 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_rl_verl.py +144 -80
- freesolo_flash_dev-1.0.47/tests/test_verl_step_metrics.py +280 -0
- freesolo_flash_dev-1.0.47/tests/test_verl_wandb_link.py +215 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/uv.lock +1 -1
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.env.example +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/Dockerfile +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/NOTICE +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/README.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/_logging.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/catalog.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/commands.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/env_setup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/env_test.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/traces.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cli/training_doc.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/multiturn_reward_scoring.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/grpo_multimodal.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/grpo_perturn_trainer.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/opd.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/opd_verl_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/opd_verl_plugin.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/opd_verl_structured.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/opd_vllm.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/rl.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/multimodal.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/opd_verl_validation.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/_worker.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/providers/weight_cache_preload.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/db.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/projects.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/flash/spec.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_async_uploads.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_b200_rollout_opt.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_grpo_cudagraphs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_grpo_perturn.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_grpo_sleep_gate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multiturn_image_rollout.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multiturn_per_turn_reward.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multiturn_rollout_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multiturn_rollout_records.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_multiturn_rollout_request_policy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_opd_full_state_resume.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_opd_verl.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_opd_vllm.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_sft_activation_shaping.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_sft_tokenize_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_sft_verl.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_single_turn_multimodal_grpo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_verl_common.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.47}/tests/test_worker_thinking.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.47
|
|
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
|
|
@@ -84,7 +84,7 @@ _HB_CLAIM_SEQ = 0
|
|
|
84
84
|
_STEP_GPU_DIAG_INTERVAL_S = 300.0
|
|
85
85
|
_SFT_HEARTBEAT_INTERVAL_S = 60.0
|
|
86
86
|
# retain at least one metric row per second across the 900s training heartbeat throttle window.
|
|
87
|
-
|
|
87
|
+
GRPO_METRIC_HISTORY_LIMIT = 1024
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
def _dump_thread_stacks(reason: str) -> None:
|
|
@@ -425,7 +425,7 @@ def make_reward_heartbeat_callback(reward_metrics=None, samples=None):
|
|
|
425
425
|
metrics["max_completion_tokens"] = int(max_completion_tokens)
|
|
426
426
|
self.metrics_last = [item for item in self.metrics_last if item["step"] != step]
|
|
427
427
|
self.metrics_last.append(metrics)
|
|
428
|
-
self.metrics_last = self.metrics_last[-
|
|
428
|
+
self.metrics_last = self.metrics_last[-GRPO_METRIC_HISTORY_LIMIT:]
|
|
429
429
|
LATEST_GRPO_METRICS_LAST[:] = self.metrics_last
|
|
430
430
|
payload = {
|
|
431
431
|
**metrics,
|
|
@@ -71,6 +71,8 @@ from flash.engine.worker.verl_common import (
|
|
|
71
71
|
clamp_engine_len,
|
|
72
72
|
latest_global_step_dir,
|
|
73
73
|
model_max_position_embeddings,
|
|
74
|
+
parse_wandb_link,
|
|
75
|
+
render_wandb_link_shim,
|
|
74
76
|
resolve_verl_python,
|
|
75
77
|
run_verl_training,
|
|
76
78
|
)
|
|
@@ -2344,13 +2346,14 @@ def run_opd_verl(spec=None) -> None:
|
|
|
2344
2346
|
entry_path = os.path.join(shim_dir, "flash_opd_verl_entry.py")
|
|
2345
2347
|
with open(entry_path, "w", encoding="utf-8") as file:
|
|
2346
2348
|
file.write("import verl\nfrom flash_opd_verl_plugin import main\nmain()\n")
|
|
2349
|
+
opd_shim_source = _render_opd_sitecustomize(
|
|
2350
|
+
save_at_steps=knobs.save_at_steps,
|
|
2351
|
+
total_steps=update_horizon,
|
|
2352
|
+
)
|
|
2353
|
+
if "wandb" in loggers:
|
|
2354
|
+
opd_shim_source += render_wandb_link_shim()
|
|
2347
2355
|
with open(os.path.join(shim_dir, "sitecustomize.py"), "w", encoding="utf-8") as file:
|
|
2348
|
-
file.write(
|
|
2349
|
-
_render_opd_sitecustomize(
|
|
2350
|
-
save_at_steps=knobs.save_at_steps,
|
|
2351
|
-
total_steps=update_horizon,
|
|
2352
|
-
)
|
|
2353
|
-
)
|
|
2356
|
+
file.write(opd_shim_source)
|
|
2354
2357
|
|
|
2355
2358
|
resume_step, resume_state = _restore_verl_resume(
|
|
2356
2359
|
local_dir,
|
|
@@ -2451,9 +2454,13 @@ def run_opd_verl(spec=None) -> None:
|
|
|
2451
2454
|
)
|
|
2452
2455
|
command = [python_bin, entry_path, *overrides]
|
|
2453
2456
|
progress = {"step": resume_step, "loss": None}
|
|
2457
|
+
wandb_link: dict[str, str | None] = {}
|
|
2454
2458
|
|
|
2455
2459
|
def on_line(line: str) -> None:
|
|
2456
2460
|
watcher.raise_if_failed()
|
|
2461
|
+
link = parse_wandb_link(line)
|
|
2462
|
+
if link is not None:
|
|
2463
|
+
wandb_link.update(link)
|
|
2457
2464
|
step_match = _VERL_STEP_RE.search(line)
|
|
2458
2465
|
if step_match is None:
|
|
2459
2466
|
return
|
|
@@ -2669,6 +2676,10 @@ def run_opd_verl(spec=None) -> None:
|
|
|
2669
2676
|
"resumed": bool(resume_step),
|
|
2670
2677
|
"wandb_project": project_name if "wandb" in loggers else None,
|
|
2671
2678
|
"wandb_run_name": experiment_name if "wandb" in loggers else None,
|
|
2679
|
+
# the sdk's link_wandb reads notes["wandb_url"]; trl gets it from the parent's live
|
|
2680
|
+
# wandb.run, verl from the child marker (see verl_common.render_wandb_link_shim).
|
|
2681
|
+
"wandb_url": wandb_link.get("wandb_url"),
|
|
2682
|
+
"wandb_id": wandb_link.get("wandb_id"),
|
|
2672
2683
|
},
|
|
2673
2684
|
)
|
|
2674
2685
|
finally:
|
|
@@ -41,7 +41,11 @@ from flash.engine.structured_outputs import (
|
|
|
41
41
|
reasoning_parser_for,
|
|
42
42
|
)
|
|
43
43
|
from flash.engine.worker._pkg import W as _w
|
|
44
|
-
from flash.engine.worker.heartbeat import
|
|
44
|
+
from flash.engine.worker.heartbeat import (
|
|
45
|
+
GRPO_METRIC_HISTORY_LIMIT,
|
|
46
|
+
LATEST_GRPO_METRICS_LAST,
|
|
47
|
+
liveness_heartbeat,
|
|
48
|
+
)
|
|
45
49
|
from flash.engine.worker.hf import _deployable_adapter_on_hf
|
|
46
50
|
from flash.engine.worker.perf import gpu_diagnostics, setup_perf_backends, wait_for_gpu
|
|
47
51
|
from flash.engine.worker.rng import backend_seed, seed_training_rngs
|
|
@@ -50,8 +54,13 @@ from flash.engine.worker.sft_verl import _hydra_val, _NvidiaSmiPeakSampler
|
|
|
50
54
|
from flash.engine.worker.verl_common import (
|
|
51
55
|
VERL_REQUIREMENT,
|
|
52
56
|
agent_loop_workers,
|
|
57
|
+
append_step_metrics,
|
|
53
58
|
clamp_engine_len,
|
|
54
59
|
model_max_position_embeddings,
|
|
60
|
+
parse_verl_metric,
|
|
61
|
+
parse_verl_step_metrics,
|
|
62
|
+
parse_wandb_link,
|
|
63
|
+
render_wandb_link_shim,
|
|
55
64
|
resolve_verl_python,
|
|
56
65
|
verl_supports_rollout_field,
|
|
57
66
|
)
|
|
@@ -370,6 +379,8 @@ def _build_verl_train_notes(
|
|
|
370
379
|
fp8_kv: bool = False,
|
|
371
380
|
wandb_project: str | None = None,
|
|
372
381
|
wandb_run_name: str | None = None,
|
|
382
|
+
wandb_url: str | None = None,
|
|
383
|
+
wandb_id: str | None = None,
|
|
373
384
|
) -> dict:
|
|
374
385
|
return {
|
|
375
386
|
"backend": "verl",
|
|
@@ -419,6 +430,10 @@ def _build_verl_train_notes(
|
|
|
419
430
|
"ppo_max_token_len_per_gpu": inp["engine_len"],
|
|
420
431
|
"wandb_project": wandb_project,
|
|
421
432
|
"wandb_run_name": wandb_run_name,
|
|
433
|
+
# the sdk's link_wandb reads notes["wandb_url"]; trl gets it from the parent's live
|
|
434
|
+
# wandb.run, verl from the child marker (see verl_common.render_wandb_link_shim).
|
|
435
|
+
"wandb_url": wandb_url,
|
|
436
|
+
"wandb_id": wandb_id,
|
|
422
437
|
"grpo_recipe": {
|
|
423
438
|
"kl_coef": inp["kl_coef"],
|
|
424
439
|
"entropy_quantile": inp["entropy_quantile"],
|
|
@@ -1420,6 +1435,10 @@ def run_rl_verl():
|
|
|
1420
1435
|
render_stop_sequences_shim(inp["stop_sequences"]),
|
|
1421
1436
|
render_structured_outputs_shim(inp["structured_outputs"]),
|
|
1422
1437
|
render_exact_save_steps_shim(inp["save_at_steps"], inp["steps"]),
|
|
1438
|
+
# gated on the key rather than the resolved logger list: that list needs python_bin,
|
|
1439
|
+
# which is resolved after this file is written. the shim is inert either way -- it only
|
|
1440
|
+
# fires when verl actually calls wandb.init, which requires wandb in the logger list.
|
|
1441
|
+
render_wandb_link_shim() if os.environ.get("WANDB_API_KEY") else "",
|
|
1423
1442
|
)
|
|
1424
1443
|
if part
|
|
1425
1444
|
)
|
|
@@ -1433,6 +1452,8 @@ def run_rl_verl():
|
|
|
1433
1452
|
# rolling buffer of recent (completion, score) so the training loop can dump one sample per step
|
|
1434
1453
|
# to the flash log, matching the trl path's #607 per-step completion dump.
|
|
1435
1454
|
recent_samples: list[tuple[str, float]] = []
|
|
1455
|
+
# filled from the child's marker line; stays empty when wandb is off (see render_wandb_link_shim).
|
|
1456
|
+
wandb_link: dict[str, str | None] = {}
|
|
1436
1457
|
_samples_lock = threading.Lock()
|
|
1437
1458
|
|
|
1438
1459
|
def _score(index: int, solution_str: str) -> float:
|
|
@@ -1544,14 +1565,21 @@ def run_rl_verl():
|
|
|
1544
1565
|
item for item in (shim_dir, os.environ.get("PYTHONPATH", "")) if item
|
|
1545
1566
|
)
|
|
1546
1567
|
step_re = re.compile(r"step:\s*(\d+)")
|
|
1547
|
-
reward_re = re.compile(r"critic/rewards/mean:([-\d.eE+]+)")
|
|
1548
|
-
loss_re = re.compile(r"actor/pg_loss:([-\d.eE+]+)")
|
|
1549
1568
|
reward_history: list[float] = []
|
|
1550
|
-
resp_len_re = re.compile(r"response_length/mean:([\d.eE+-]+)")
|
|
1551
1569
|
resp_len_history: list[float] = []
|
|
1552
1570
|
loss_curve: list[float] = []
|
|
1553
1571
|
last_dump_step = [-1]
|
|
1554
|
-
|
|
1572
|
+
# per-step backlog for `flash runs log -f`, rebuilt from verl's own step lines because its
|
|
1573
|
+
# trainer runs out of process and cannot host trl's callback. read by the liveness thread
|
|
1574
|
+
# below, so mutate it in place (append_step_metrics) rather than rebinding.
|
|
1575
|
+
metrics_last: list[dict] = []
|
|
1576
|
+
sent_first_metrics = False
|
|
1577
|
+
with liveness_heartbeat(
|
|
1578
|
+
"rl_step",
|
|
1579
|
+
progress=_progress,
|
|
1580
|
+
fields=lambda: {"metrics_last": list(metrics_last)},
|
|
1581
|
+
progress_step=True,
|
|
1582
|
+
):
|
|
1555
1583
|
proc = subprocess.Popen(
|
|
1556
1584
|
[python_bin, "-m", "verl.trainer.main_ppo", *overrides],
|
|
1557
1585
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, env=env_for_verl,
|
|
@@ -1560,6 +1588,9 @@ def run_rl_verl():
|
|
|
1560
1588
|
try:
|
|
1561
1589
|
for line in proc.stdout:
|
|
1562
1590
|
print(f"[verl] {line}", end="", flush=True)
|
|
1591
|
+
link = parse_wandb_link(line)
|
|
1592
|
+
if link is not None:
|
|
1593
|
+
wandb_link.update(link)
|
|
1563
1594
|
m = step_re.search(line)
|
|
1564
1595
|
if m:
|
|
1565
1596
|
step_box[0] = int(m.group(1))
|
|
@@ -1574,16 +1605,43 @@ def run_rl_verl():
|
|
|
1574
1605
|
f"[rl-verl] step {step_box[0]} sample (reward={samp[1]:.3f}): {preview}",
|
|
1575
1606
|
flush=True,
|
|
1576
1607
|
)
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1608
|
+
step_metrics = parse_verl_step_metrics(line)
|
|
1609
|
+
if step_metrics is not None:
|
|
1610
|
+
# a run constant rather than a verl metric, so it is stamped here the way
|
|
1611
|
+
# trl's callback reads it off args.max_completion_length.
|
|
1612
|
+
step_metrics["max_completion_tokens"] = inp["max_completion"]
|
|
1613
|
+
append_step_metrics(
|
|
1614
|
+
metrics_last, step_metrics, limit=GRPO_METRIC_HISTORY_LIMIT
|
|
1615
|
+
)
|
|
1616
|
+
# the worker's error path reads this global, so a run that dies mid-training
|
|
1617
|
+
# still reports the steps it did complete (worker/__init__.py:_err_metrics).
|
|
1618
|
+
LATEST_GRPO_METRICS_LAST[:] = metrics_last
|
|
1619
|
+
# the rl_train_start ping arms the 900s rl_step throttle, and the liveness
|
|
1620
|
+
# daemon never forces, so the first backlog would stay invisible for 15
|
|
1621
|
+
# minutes. force it through the way trl does (heartbeat.py
|
|
1622
|
+
# force_first_samples), and keep retrying until one commits: the daemon may
|
|
1623
|
+
# claim this step first, which is fine because its payload carries the same
|
|
1624
|
+
# backlog. only the FIRST is forced, so the hf commit cap stays protected.
|
|
1625
|
+
if not sent_first_metrics:
|
|
1626
|
+
sent_first_metrics = _w.heartbeat(
|
|
1627
|
+
"rl_step",
|
|
1628
|
+
force=True,
|
|
1629
|
+
step=step_metrics["step"],
|
|
1630
|
+
metrics_last=list(metrics_last),
|
|
1631
|
+
gpu=gpu_diagnostics(include_torch=False),
|
|
1632
|
+
)
|
|
1633
|
+
# per-step series for train_meta observability parity. these live on the same
|
|
1634
|
+
# line as everything else: verl's only console metric sink is LocalLogger,
|
|
1635
|
+
# which always prints "step:N - ..." (verl/utils/logger/aggregate_logger.py),
|
|
1636
|
+
# so a line without a step carries no metric to collect.
|
|
1637
|
+
for verl_key, sink in (
|
|
1638
|
+
("critic/rewards/mean", reward_history),
|
|
1639
|
+
("actor/pg_loss", loss_curve),
|
|
1640
|
+
("response_length/mean", resp_len_history),
|
|
1641
|
+
):
|
|
1642
|
+
value = parse_verl_metric(line, verl_key)
|
|
1643
|
+
if value is not None:
|
|
1644
|
+
sink.append(value)
|
|
1587
1645
|
rc = proc.wait()
|
|
1588
1646
|
except BaseException:
|
|
1589
1647
|
# the stream loop died (upload error, cancel, oom in the parent): a still-running
|
|
@@ -1631,6 +1689,7 @@ def run_rl_verl():
|
|
|
1631
1689
|
with liveness_heartbeat(
|
|
1632
1690
|
"rl_finalizing",
|
|
1633
1691
|
progress=lambda: steps_run,
|
|
1692
|
+
fields=lambda: {"metrics_last": list(metrics_last)},
|
|
1634
1693
|
progress_step=True,
|
|
1635
1694
|
keepalive=True,
|
|
1636
1695
|
):
|
|
@@ -1644,7 +1703,13 @@ def run_rl_verl():
|
|
|
1644
1703
|
if final_save_due(steps_run, inp["save_at_steps"]):
|
|
1645
1704
|
_w.publish_deployable_checkpoint(adapter_dir, steps_run)
|
|
1646
1705
|
|
|
1647
|
-
_w.heartbeat(
|
|
1706
|
+
_w.heartbeat(
|
|
1707
|
+
"rl_trained",
|
|
1708
|
+
train_wall=train_wall,
|
|
1709
|
+
step=steps_run,
|
|
1710
|
+
gpu=gpu_diagnostics(),
|
|
1711
|
+
metrics_last=list(metrics_last),
|
|
1712
|
+
)
|
|
1648
1713
|
_w.write_train_meta(
|
|
1649
1714
|
phase="rl",
|
|
1650
1715
|
adapter_dir=adapter_dir,
|
|
@@ -1652,6 +1717,7 @@ def run_rl_verl():
|
|
|
1652
1717
|
train_wall=train_wall,
|
|
1653
1718
|
setup_seconds=setup_seconds,
|
|
1654
1719
|
train_tokens=0,
|
|
1720
|
+
heartbeat_fields={"metrics_last": list(metrics_last)},
|
|
1655
1721
|
generated_tokens=int(
|
|
1656
1722
|
sum(resp_len_history) / max(1, len(resp_len_history))
|
|
1657
1723
|
* steps_run * inp["prompts_per_step"] * inp["group_size"]
|
|
@@ -1670,5 +1736,7 @@ def run_rl_verl():
|
|
|
1670
1736
|
fp8_kv=fp8_kv,
|
|
1671
1737
|
wandb_project=project_name if "wandb" in loggers else None,
|
|
1672
1738
|
wandb_run_name=experiment_name if "wandb" in loggers else None,
|
|
1739
|
+
wandb_url=wandb_link.get("wandb_url"),
|
|
1740
|
+
wandb_id=wandb_link.get("wandb_id"),
|
|
1673
1741
|
),
|
|
1674
1742
|
)
|
|
@@ -42,6 +42,8 @@ from flash.engine.worker.sft import (
|
|
|
42
42
|
from flash.engine.worker.verl_common import (
|
|
43
43
|
export_peft_adapter,
|
|
44
44
|
latest_global_step_dir,
|
|
45
|
+
parse_wandb_link,
|
|
46
|
+
render_wandb_link_shim,
|
|
45
47
|
resolve_verl_python,
|
|
46
48
|
run_verl_training,
|
|
47
49
|
stamp_adapter_dir_provenance,
|
|
@@ -1282,6 +1284,8 @@ def run_sft_verl(spec=None) -> None:
|
|
|
1282
1284
|
total_steps=update_horizon,
|
|
1283
1285
|
reentrant_gradient_checkpointing=reentrant_gradient_checkpointing,
|
|
1284
1286
|
)
|
|
1287
|
+
if "wandb" in loggers:
|
|
1288
|
+
shim_source += render_wandb_link_shim()
|
|
1285
1289
|
with open(os.path.join(shim_dir, "sitecustomize.py"), "w", encoding="utf-8") as file:
|
|
1286
1290
|
file.write(shim_source)
|
|
1287
1291
|
with open(custom_dataset_path, "w", encoding="utf-8") as file:
|
|
@@ -1327,12 +1331,16 @@ def run_sft_verl(spec=None) -> None:
|
|
|
1327
1331
|
resume_step,
|
|
1328
1332
|
)
|
|
1329
1333
|
loraplus_applied = resume_step >= update_horizon
|
|
1334
|
+
wandb_link: dict[str, str | None] = {}
|
|
1330
1335
|
|
|
1331
1336
|
def on_line(line: str) -> None:
|
|
1332
1337
|
nonlocal loraplus_applied
|
|
1333
1338
|
watcher.raise_if_failed()
|
|
1334
1339
|
if _LORAPLUS_READY_MARKER in line:
|
|
1335
1340
|
loraplus_applied = True
|
|
1341
|
+
link = parse_wandb_link(line)
|
|
1342
|
+
if link is not None:
|
|
1343
|
+
wandb_link.update(link)
|
|
1336
1344
|
step_match = _VERL_STEP_RE.search(line)
|
|
1337
1345
|
if step_match is None:
|
|
1338
1346
|
return
|
|
@@ -1458,5 +1466,9 @@ def run_sft_verl(spec=None) -> None:
|
|
|
1458
1466
|
"ulysses_sequence_parallel_size": gpu_count,
|
|
1459
1467
|
"wandb_project": project_name if "wandb" in loggers else None,
|
|
1460
1468
|
"wandb_run_name": experiment_name if "wandb" in loggers else None,
|
|
1469
|
+
# the sdk's link_wandb reads notes["wandb_url"]; trl gets it from the parent's live
|
|
1470
|
+
# wandb.run, verl from the child marker (see verl_common.render_wandb_link_shim).
|
|
1471
|
+
"wandb_url": wandb_link.get("wandb_url"),
|
|
1472
|
+
"wandb_id": wandb_link.get("wandb_id"),
|
|
1461
1473
|
},
|
|
1462
1474
|
)
|
|
@@ -12,6 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
import contextlib
|
|
14
14
|
import json
|
|
15
|
+
import math
|
|
15
16
|
import os
|
|
16
17
|
import re
|
|
17
18
|
import shutil
|
|
@@ -317,3 +318,175 @@ def _kill_process_group(proc: subprocess.Popen) -> None:
|
|
|
317
318
|
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
|
|
318
319
|
with contextlib.suppress(subprocess.TimeoutExpired):
|
|
319
320
|
proc.wait(timeout=10)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
# --------------------------- w&b run link (all three verl backends) ---------------------------
|
|
324
|
+
# trl spreads wandb_run_info() into its notes, giving the sdk's link_wandb a clickable
|
|
325
|
+
# notes["wandb_url"]. verl calls wandb.init INSIDE the training subprocess, so the flash parent's
|
|
326
|
+
# wandb.run is None and that spread would be a silent no-op. the url is not derivable up here
|
|
327
|
+
# either: it needs entity/project/runs/<wandb-generated-id>, and flash only knows the project and
|
|
328
|
+
# its own run NAME. so the child reports it back over the marker channel the parent already scans.
|
|
329
|
+
FLASH_WANDB_LINK_MARKER = "FLASH_WANDB_LINK"
|
|
330
|
+
|
|
331
|
+
_WANDB_LINK_RE = re.compile(rf"{FLASH_WANDB_LINK_MARKER}\s+(\{{.*\}})\s*$")
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def render_wandb_link_shim() -> str:
|
|
335
|
+
"""child-side sitecustomize fragment that reports the live w&b run's url and id.
|
|
336
|
+
|
|
337
|
+
wraps wandb.init rather than reading wandb.run at import time: sitecustomize runs long before
|
|
338
|
+
verl's tracking module initializes the run, so anything read here would always be None.
|
|
339
|
+
|
|
340
|
+
never raises. wandb is optional and a logging link must not be able to abort paid training, so
|
|
341
|
+
every failure path leaves the run unlinked instead of dead.
|
|
342
|
+
"""
|
|
343
|
+
return f'''
|
|
344
|
+
# --- flash: report the w&b run link to the parent (see verl_common.render_wandb_link_shim) ---
|
|
345
|
+
try:
|
|
346
|
+
import json as _flash_wandb_json
|
|
347
|
+
|
|
348
|
+
import wandb as _flash_wandb
|
|
349
|
+
|
|
350
|
+
_flash_wandb_init = _flash_wandb.init
|
|
351
|
+
|
|
352
|
+
def _flash_wandb_init_reporting(*args, **kwargs):
|
|
353
|
+
_run = _flash_wandb_init(*args, **kwargs)
|
|
354
|
+
try:
|
|
355
|
+
_url = getattr(_run, "url", None)
|
|
356
|
+
_id = getattr(_run, "id", None)
|
|
357
|
+
if _url:
|
|
358
|
+
print(
|
|
359
|
+
"{FLASH_WANDB_LINK_MARKER} "
|
|
360
|
+
+ _flash_wandb_json.dumps({{"wandb_url": _url, "wandb_id": _id}}),
|
|
361
|
+
flush=True,
|
|
362
|
+
)
|
|
363
|
+
except Exception:
|
|
364
|
+
pass
|
|
365
|
+
return _run
|
|
366
|
+
|
|
367
|
+
_flash_wandb.init = _flash_wandb_init_reporting
|
|
368
|
+
except Exception:
|
|
369
|
+
pass
|
|
370
|
+
'''
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def parse_wandb_link(line: str) -> dict | None:
|
|
374
|
+
"""the {{wandb_url, wandb_id}} a marker line carries, or None for every other line.
|
|
375
|
+
|
|
376
|
+
returns None rather than raising on a malformed payload: this parses child stdout, and a
|
|
377
|
+
truncated or interleaved line under multi-rank logging must not take down the run.
|
|
378
|
+
"""
|
|
379
|
+
match = _WANDB_LINK_RE.search(line)
|
|
380
|
+
if match is None:
|
|
381
|
+
return None
|
|
382
|
+
try:
|
|
383
|
+
payload = json.loads(match.group(1))
|
|
384
|
+
except ValueError:
|
|
385
|
+
return None
|
|
386
|
+
if not isinstance(payload, dict):
|
|
387
|
+
return None
|
|
388
|
+
url = payload.get("wandb_url")
|
|
389
|
+
# https only: the sdk renders this as a clickable dashboard link, and child stdout also carries
|
|
390
|
+
# rollout text, so the field must not be able to become an arbitrary scheme.
|
|
391
|
+
if not isinstance(url, str) or not url.startswith("https://"):
|
|
392
|
+
return None
|
|
393
|
+
wandb_id = payload.get("wandb_id")
|
|
394
|
+
return {"wandb_url": url, "wandb_id": wandb_id if isinstance(wandb_id, str) else None}
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
# --------------------------- per-step grpo metrics (verl -> `flash runs log -f`) ---------------------------
|
|
398
|
+
# trl feeds `metrics_last` from a TrainerCallback (heartbeat.make_reward_heartbeat_callback), which
|
|
399
|
+
# verl cannot use: its trainer runs out of process. verl's LocalLogger prints exactly one line per
|
|
400
|
+
# optimizer update -- "step:N - key:value - key:value" over every scalar metric -- so the parent
|
|
401
|
+
# reconstructs the same backlog from that line. the payload schema is the CLI's, not verl's: keys
|
|
402
|
+
# below are what flash/cli/commands.py:_FOLLOW_METRIC_FIELDS renders.
|
|
403
|
+
#
|
|
404
|
+
# not anchored at line start: ray tags worker stdout with a "(TaskRunner pid=123) " prefix, so an
|
|
405
|
+
# anchored match would parse nothing at all in production. the existing progress regex in rl_verl
|
|
406
|
+
# is unanchored for the same reason.
|
|
407
|
+
_VERL_STEP_RE = re.compile(r"(?:^|\s)step:(\d+) - ")
|
|
408
|
+
|
|
409
|
+
# verl metric key -> flash `metrics_last` field. verl has no counterpart for trl's
|
|
410
|
+
# frac_reward_zero_std (an advantage-collapse fraction trl computes per group), so that column is
|
|
411
|
+
# simply absent for verl runs rather than faked; the renderer skips fields it does not find.
|
|
412
|
+
_VERL_METRIC_FIELDS = (
|
|
413
|
+
("critic/rewards/mean", "reward"),
|
|
414
|
+
("actor/grad_norm", "grad_norm"),
|
|
415
|
+
("actor/kl_loss", "kl"),
|
|
416
|
+
("actor/entropy", "entropy"),
|
|
417
|
+
("response_length/mean", "mean_completion_tokens"),
|
|
418
|
+
("response_length/clip_ratio", "truncation_rate"),
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
# verl reduces most metrics with np.mean and formats them through pprint, so under numpy>=2 a value
|
|
422
|
+
# prints as "np.float32(1.25)" rather than "1.25". verl's own requirements pin numpy<2, but the
|
|
423
|
+
# production interpreter comes from FLASH_VERL_PYTHON (a prebuilt image flash does not own), so
|
|
424
|
+
# accept both spellings -- the numpy-2 form would otherwise drop these columns silently.
|
|
425
|
+
_NUMPY_SCALAR_RE = re.compile(r"^np\.\w+\((.*)\)$")
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _metric_value(raw: str) -> float | None:
|
|
429
|
+
"""one verl-printed scalar as a finite float, or None when it is not usable."""
|
|
430
|
+
wrapper = _NUMPY_SCALAR_RE.match(raw)
|
|
431
|
+
if wrapper is not None:
|
|
432
|
+
raw = wrapper.group(1)
|
|
433
|
+
try:
|
|
434
|
+
value = float(raw)
|
|
435
|
+
except ValueError:
|
|
436
|
+
return None
|
|
437
|
+
# nan/inf survive float() ("nan", "inf") but would render as a meaningless column and can poison
|
|
438
|
+
# a json payload downstream, so drop them the way the trl callback does.
|
|
439
|
+
return value if math.isfinite(value) else None
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def parse_verl_metric(line: str, verl_key: str) -> float | None:
|
|
443
|
+
"""one verl metric's finite float value from a step line, or None when absent.
|
|
444
|
+
|
|
445
|
+
anchors the key on a separator so a metric whose name merely ends with another's
|
|
446
|
+
(response_length_non_aborted/mean vs response_length/mean) cannot cross-match, and accepts the
|
|
447
|
+
numpy>=2 ``np.float64(...)`` spelling (see _NUMPY_SCALAR_RE).
|
|
448
|
+
"""
|
|
449
|
+
hit = re.search(rf"(?:^|[\s-]){re.escape(verl_key)}:(\S+)", line)
|
|
450
|
+
return None if hit is None else _metric_value(hit.group(1))
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def parse_verl_step_metrics(line: str) -> dict | None:
|
|
454
|
+
"""the flash `metrics_last` entry a verl step line carries, or None when it carries none.
|
|
455
|
+
|
|
456
|
+
returns None rather than raising: this parses child stdout under multi-rank logging, where a
|
|
457
|
+
truncated or interleaved line must not take down a paid run.
|
|
458
|
+
|
|
459
|
+
a step line with no renderable metric yields None rather than a bare ``{"step": n}``: verl logs
|
|
460
|
+
its pre-training validation pass as its own record at the *current* step counter
|
|
461
|
+
(ray_trainer.py `logger.log(data=val_metrics, step=self.global_steps)`), and every key on that
|
|
462
|
+
line is namespaced val-core/ or val-aux/. keeping it would render a row with a step number and
|
|
463
|
+
no metrics, and -- because the backlog is deduplicated by step -- a resumed run's validation
|
|
464
|
+
pass would land on the resume step and displace a real training row.
|
|
465
|
+
"""
|
|
466
|
+
match = _VERL_STEP_RE.search(line)
|
|
467
|
+
if match is None:
|
|
468
|
+
return None
|
|
469
|
+
metrics: dict[str, float | int] = {}
|
|
470
|
+
for verl_key, flash_key in _VERL_METRIC_FIELDS:
|
|
471
|
+
value = parse_verl_metric(line, verl_key)
|
|
472
|
+
if value is not None:
|
|
473
|
+
metrics[flash_key] = value
|
|
474
|
+
if not metrics:
|
|
475
|
+
return None
|
|
476
|
+
return {"step": int(match.group(1)), **metrics}
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def append_step_metrics(backlog: list[dict], metrics: dict, *, limit: int) -> None:
|
|
480
|
+
"""record one step in a bounded, de-duplicated backlog, mirroring the trl callback.
|
|
481
|
+
|
|
482
|
+
verl reprints a step on a validation pass, and a resumed run replays its resume step, so a
|
|
483
|
+
repeat must replace rather than append -- otherwise the CLI renders the same step twice.
|
|
484
|
+
|
|
485
|
+
the heartbeat thread reads ``backlog`` while the stdout loop writes it, so the new contents are
|
|
486
|
+
published in ONE slice assignment: a filter/append/truncate sequence would let that reader
|
|
487
|
+
observe a torn intermediate state with the step momentarily missing.
|
|
488
|
+
"""
|
|
489
|
+
step = metrics.get("step")
|
|
490
|
+
kept = [item for item in backlog if item.get("step") != step]
|
|
491
|
+
kept.append(metrics)
|
|
492
|
+
backlog[:] = kept[-limit:]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "freesolo-flash-dev"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.47"
|
|
4
4
|
description = "Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
# RunPod Flash supports Python 3.11-3.12 (not 3.13 yet).
|
|
@@ -116,7 +116,7 @@ artifacts = ["flash/py.typed"]
|
|
|
116
116
|
# auto-published by .github/workflows/publish-dev.yml: a push to `dev` whose version isn't yet on
|
|
117
117
|
# PyPI publishes it; pushes that don't change it find it already published and no-op. So cutting a
|
|
118
118
|
# dev-channel release = bump this (and [project].version) and merge to `dev`.
|
|
119
|
-
version = "1.0.
|
|
119
|
+
version = "1.0.47"
|
|
120
120
|
|
|
121
121
|
[tool.pytest.ini_options]
|
|
122
122
|
pythonpath = ["."]
|