freesolo-flash-dev 1.0.45__tar.gz → 1.0.46__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.46}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl.py +17 -6
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rl_verl.py +19 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/sft_verl.py +12 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/verl_common.py +74 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_rl_verl.py +120 -79
- freesolo_flash_dev-1.0.46/tests/test_verl_wandb_link.py +215 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/uv.lock +1 -1
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.env.example +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/Dockerfile +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/NOTICE +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/README.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_logging.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/catalog.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/commands.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/env_setup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/env_test.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/traces.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cli/training_doc.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/multiturn_reward_scoring.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/grpo_multimodal.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/grpo_perturn_trainer.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl_plugin.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_verl_structured.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/opd_vllm.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rl.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/multimodal.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/opd_verl_validation.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/_worker.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/providers/weight_cache_preload.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/db.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/projects.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/flash/spec.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_async_uploads.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_b200_rollout_opt.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_cudagraphs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_perturn.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_grpo_sleep_gate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_image_rollout.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_per_turn_reward.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout_records.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_multiturn_rollout_request_policy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_full_state_resume.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_verl.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_opd_vllm.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_activation_shaping.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_tokenize_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_sft_verl.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_single_turn_multimodal_grpo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_verl_common.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.0.45 → freesolo_flash_dev-1.0.46}/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.46
|
|
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
|
|
@@ -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:
|
|
@@ -52,6 +52,8 @@ from flash.engine.worker.verl_common import (
|
|
|
52
52
|
agent_loop_workers,
|
|
53
53
|
clamp_engine_len,
|
|
54
54
|
model_max_position_embeddings,
|
|
55
|
+
parse_wandb_link,
|
|
56
|
+
render_wandb_link_shim,
|
|
55
57
|
resolve_verl_python,
|
|
56
58
|
verl_supports_rollout_field,
|
|
57
59
|
)
|
|
@@ -370,6 +372,8 @@ def _build_verl_train_notes(
|
|
|
370
372
|
fp8_kv: bool = False,
|
|
371
373
|
wandb_project: str | None = None,
|
|
372
374
|
wandb_run_name: str | None = None,
|
|
375
|
+
wandb_url: str | None = None,
|
|
376
|
+
wandb_id: str | None = None,
|
|
373
377
|
) -> dict:
|
|
374
378
|
return {
|
|
375
379
|
"backend": "verl",
|
|
@@ -419,6 +423,10 @@ def _build_verl_train_notes(
|
|
|
419
423
|
"ppo_max_token_len_per_gpu": inp["engine_len"],
|
|
420
424
|
"wandb_project": wandb_project,
|
|
421
425
|
"wandb_run_name": wandb_run_name,
|
|
426
|
+
# the sdk's link_wandb reads notes["wandb_url"]; trl gets it from the parent's live
|
|
427
|
+
# wandb.run, verl from the child marker (see verl_common.render_wandb_link_shim).
|
|
428
|
+
"wandb_url": wandb_url,
|
|
429
|
+
"wandb_id": wandb_id,
|
|
422
430
|
"grpo_recipe": {
|
|
423
431
|
"kl_coef": inp["kl_coef"],
|
|
424
432
|
"entropy_quantile": inp["entropy_quantile"],
|
|
@@ -1420,6 +1428,10 @@ def run_rl_verl():
|
|
|
1420
1428
|
render_stop_sequences_shim(inp["stop_sequences"]),
|
|
1421
1429
|
render_structured_outputs_shim(inp["structured_outputs"]),
|
|
1422
1430
|
render_exact_save_steps_shim(inp["save_at_steps"], inp["steps"]),
|
|
1431
|
+
# gated on the key rather than the resolved logger list: that list needs python_bin,
|
|
1432
|
+
# which is resolved after this file is written. the shim is inert either way -- it only
|
|
1433
|
+
# fires when verl actually calls wandb.init, which requires wandb in the logger list.
|
|
1434
|
+
render_wandb_link_shim() if os.environ.get("WANDB_API_KEY") else "",
|
|
1423
1435
|
)
|
|
1424
1436
|
if part
|
|
1425
1437
|
)
|
|
@@ -1433,6 +1445,8 @@ def run_rl_verl():
|
|
|
1433
1445
|
# rolling buffer of recent (completion, score) so the training loop can dump one sample per step
|
|
1434
1446
|
# to the flash log, matching the trl path's #607 per-step completion dump.
|
|
1435
1447
|
recent_samples: list[tuple[str, float]] = []
|
|
1448
|
+
# filled from the child's marker line; stays empty when wandb is off (see render_wandb_link_shim).
|
|
1449
|
+
wandb_link: dict[str, str | None] = {}
|
|
1436
1450
|
_samples_lock = threading.Lock()
|
|
1437
1451
|
|
|
1438
1452
|
def _score(index: int, solution_str: str) -> float:
|
|
@@ -1560,6 +1574,9 @@ def run_rl_verl():
|
|
|
1560
1574
|
try:
|
|
1561
1575
|
for line in proc.stdout:
|
|
1562
1576
|
print(f"[verl] {line}", end="", flush=True)
|
|
1577
|
+
link = parse_wandb_link(line)
|
|
1578
|
+
if link is not None:
|
|
1579
|
+
wandb_link.update(link)
|
|
1563
1580
|
m = step_re.search(line)
|
|
1564
1581
|
if m:
|
|
1565
1582
|
step_box[0] = int(m.group(1))
|
|
@@ -1670,5 +1687,7 @@ def run_rl_verl():
|
|
|
1670
1687
|
fp8_kv=fp8_kv,
|
|
1671
1688
|
wandb_project=project_name if "wandb" in loggers else None,
|
|
1672
1689
|
wandb_run_name=experiment_name if "wandb" in loggers else None,
|
|
1690
|
+
wandb_url=wandb_link.get("wandb_url"),
|
|
1691
|
+
wandb_id=wandb_link.get("wandb_id"),
|
|
1673
1692
|
),
|
|
1674
1693
|
)
|
|
@@ -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
|
)
|
|
@@ -317,3 +317,77 @@ def _kill_process_group(proc: subprocess.Popen) -> None:
|
|
|
317
317
|
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
|
|
318
318
|
with contextlib.suppress(subprocess.TimeoutExpired):
|
|
319
319
|
proc.wait(timeout=10)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
# --------------------------- w&b run link (all three verl backends) ---------------------------
|
|
323
|
+
# trl spreads wandb_run_info() into its notes, giving the sdk's link_wandb a clickable
|
|
324
|
+
# notes["wandb_url"]. verl calls wandb.init INSIDE the training subprocess, so the flash parent's
|
|
325
|
+
# wandb.run is None and that spread would be a silent no-op. the url is not derivable up here
|
|
326
|
+
# either: it needs entity/project/runs/<wandb-generated-id>, and flash only knows the project and
|
|
327
|
+
# its own run NAME. so the child reports it back over the marker channel the parent already scans.
|
|
328
|
+
FLASH_WANDB_LINK_MARKER = "FLASH_WANDB_LINK"
|
|
329
|
+
|
|
330
|
+
_WANDB_LINK_RE = re.compile(rf"{FLASH_WANDB_LINK_MARKER}\s+(\{{.*\}})\s*$")
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def render_wandb_link_shim() -> str:
|
|
334
|
+
"""child-side sitecustomize fragment that reports the live w&b run's url and id.
|
|
335
|
+
|
|
336
|
+
wraps wandb.init rather than reading wandb.run at import time: sitecustomize runs long before
|
|
337
|
+
verl's tracking module initializes the run, so anything read here would always be None.
|
|
338
|
+
|
|
339
|
+
never raises. wandb is optional and a logging link must not be able to abort paid training, so
|
|
340
|
+
every failure path leaves the run unlinked instead of dead.
|
|
341
|
+
"""
|
|
342
|
+
return f'''
|
|
343
|
+
# --- flash: report the w&b run link to the parent (see verl_common.render_wandb_link_shim) ---
|
|
344
|
+
try:
|
|
345
|
+
import json as _flash_wandb_json
|
|
346
|
+
|
|
347
|
+
import wandb as _flash_wandb
|
|
348
|
+
|
|
349
|
+
_flash_wandb_init = _flash_wandb.init
|
|
350
|
+
|
|
351
|
+
def _flash_wandb_init_reporting(*args, **kwargs):
|
|
352
|
+
_run = _flash_wandb_init(*args, **kwargs)
|
|
353
|
+
try:
|
|
354
|
+
_url = getattr(_run, "url", None)
|
|
355
|
+
_id = getattr(_run, "id", None)
|
|
356
|
+
if _url:
|
|
357
|
+
print(
|
|
358
|
+
"{FLASH_WANDB_LINK_MARKER} "
|
|
359
|
+
+ _flash_wandb_json.dumps({{"wandb_url": _url, "wandb_id": _id}}),
|
|
360
|
+
flush=True,
|
|
361
|
+
)
|
|
362
|
+
except Exception:
|
|
363
|
+
pass
|
|
364
|
+
return _run
|
|
365
|
+
|
|
366
|
+
_flash_wandb.init = _flash_wandb_init_reporting
|
|
367
|
+
except Exception:
|
|
368
|
+
pass
|
|
369
|
+
'''
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def parse_wandb_link(line: str) -> dict | None:
|
|
373
|
+
"""the {{wandb_url, wandb_id}} a marker line carries, or None for every other line.
|
|
374
|
+
|
|
375
|
+
returns None rather than raising on a malformed payload: this parses child stdout, and a
|
|
376
|
+
truncated or interleaved line under multi-rank logging must not take down the run.
|
|
377
|
+
"""
|
|
378
|
+
match = _WANDB_LINK_RE.search(line)
|
|
379
|
+
if match is None:
|
|
380
|
+
return None
|
|
381
|
+
try:
|
|
382
|
+
payload = json.loads(match.group(1))
|
|
383
|
+
except ValueError:
|
|
384
|
+
return None
|
|
385
|
+
if not isinstance(payload, dict):
|
|
386
|
+
return None
|
|
387
|
+
url = payload.get("wandb_url")
|
|
388
|
+
# https only: the sdk renders this as a clickable dashboard link, and child stdout also carries
|
|
389
|
+
# rollout text, so the field must not be able to become an arbitrary scheme.
|
|
390
|
+
if not isinstance(url, str) or not url.startswith("https://"):
|
|
391
|
+
return None
|
|
392
|
+
wandb_id = payload.get("wandb_id")
|
|
393
|
+
return {"wandb_url": url, "wandb_id": wandb_id if isinstance(wandb_id, str) else None}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "freesolo-flash-dev"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.46"
|
|
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.46"
|
|
120
120
|
|
|
121
121
|
[tool.pytest.ini_options]
|
|
122
122
|
pythonpath = ["."]
|
|
@@ -322,48 +322,8 @@ def test_resolver_clamps_prompt_budget_with_the_engine(monkeypatch):
|
|
|
322
322
|
# UNCLAMPED context. those prompts plus the completion allowance overflow the engine vllm was
|
|
323
323
|
# actually given, so they die at rollout instead of training on the shorter context. every
|
|
324
324
|
# length must descend from one clamped value.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
class _Env:
|
|
329
|
-
multi_turn = False
|
|
330
|
-
is_tool_env = False
|
|
331
|
-
|
|
332
|
-
def dataset(self):
|
|
333
|
-
return [{"index": i} for i in range(8)]
|
|
334
|
-
|
|
335
|
-
def prompt_messages(self, ex):
|
|
336
|
-
return [{"role": "user", "content": f"question {ex['index']}"}]
|
|
337
|
-
|
|
338
|
-
class _Tokenizer:
|
|
339
|
-
pad_token = None
|
|
340
|
-
eos_token = "<eos>"
|
|
341
|
-
|
|
342
|
-
def apply_chat_template(self, messages, **kwargs):
|
|
343
|
-
return messages[0]["content"]
|
|
344
|
-
|
|
345
|
-
def __call__(self, text, **kwargs):
|
|
346
|
-
return SimpleNamespace(input_ids=[1])
|
|
347
|
-
|
|
348
|
-
spec = JobSpec.from_dict(
|
|
349
|
-
{
|
|
350
|
-
"model": "Qwen/Qwen3.5-0.8B",
|
|
351
|
-
"algorithm": "grpo",
|
|
352
|
-
# asks for twice the architecture's context.
|
|
353
|
-
"train": {"batch_size": 4, "epochs": 1, "max_context_tokens": 65536},
|
|
354
|
-
}
|
|
355
|
-
)
|
|
356
|
-
monkeypatch.setattr(W, "JOB_SPEC", spec, raising=False)
|
|
357
|
-
monkeypatch.setattr(W, "SEED", 42, raising=False)
|
|
358
|
-
monkeypatch.setattr(W, "THINKING", False, raising=False)
|
|
359
|
-
monkeypatch.setattr(W, "require_active_env", lambda: _Env(), raising=False)
|
|
360
|
-
monkeypatch.setattr(W, "grpo_overrides", lambda: {}, raising=False)
|
|
361
|
-
monkeypatch.setattr(W, "grpo_mask_truncated_completions", lambda train: False, raising=False)
|
|
362
|
-
monkeypatch.setattr(W, "load_tokenizer", lambda *args, **kwargs: _Tokenizer(), raising=False)
|
|
363
|
-
monkeypatch.setattr(rl_verl, "seed_training_rngs", lambda seed: None)
|
|
364
|
-
monkeypatch.setattr(rl_verl, "model_max_position_embeddings", lambda *a, **k: 32768)
|
|
365
|
-
|
|
366
|
-
inp = rl_verl._resolve_single_turn_inputs()
|
|
325
|
+
# asks for twice the architecture's context (model_max_position_embeddings is pinned to 32768).
|
|
326
|
+
inp = _capability_resolve(monkeypatch, _capability_env(), train={"max_context_tokens": 65536})
|
|
367
327
|
assert inp["engine_len"] == 32768
|
|
368
328
|
# the prompt filter's budget is carved out of the clamped engine, not the requested 65536.
|
|
369
329
|
assert inp["max_prompt_len"] + inp["max_completion"] == 32768
|
|
@@ -388,47 +348,12 @@ def test_resolver_clamps_prompt_budget_with_the_engine(monkeypatch):
|
|
|
388
348
|
|
|
389
349
|
def _save_steps_inputs(monkeypatch, *, save_at_steps=None, save_every=None, max_steps=100):
|
|
390
350
|
"""resolve grpo verl inputs for a job with (or without) exact save steps."""
|
|
391
|
-
|
|
392
|
-
from flash.spec import JobSpec
|
|
393
|
-
|
|
394
|
-
class _Env:
|
|
395
|
-
multi_turn = False
|
|
396
|
-
is_tool_env = False
|
|
397
|
-
|
|
398
|
-
def dataset(self):
|
|
399
|
-
return [{"index": i} for i in range(8)]
|
|
400
|
-
|
|
401
|
-
def prompt_messages(self, ex):
|
|
402
|
-
return [{"role": "user", "content": f"question {ex['index']}"}]
|
|
403
|
-
|
|
404
|
-
class _Tokenizer:
|
|
405
|
-
pad_token = None
|
|
406
|
-
eos_token = "<eos>"
|
|
407
|
-
|
|
408
|
-
def apply_chat_template(self, messages, **kwargs):
|
|
409
|
-
return messages[0]["content"]
|
|
410
|
-
|
|
411
|
-
def __call__(self, text, **kwargs):
|
|
412
|
-
return SimpleNamespace(input_ids=[1])
|
|
413
|
-
|
|
414
|
-
train: dict = {"batch_size": 4, "epochs": 1, "max_steps": max_steps}
|
|
351
|
+
train: dict = {"max_steps": max_steps}
|
|
415
352
|
if save_at_steps is not None:
|
|
416
353
|
train["save_at_steps"] = list(save_at_steps)
|
|
417
354
|
if save_every is not None:
|
|
418
355
|
train["save_every"] = save_every
|
|
419
|
-
|
|
420
|
-
{"model": "Qwen/Qwen3.5-0.8B", "algorithm": "grpo", "train": train}
|
|
421
|
-
)
|
|
422
|
-
monkeypatch.setattr(W, "JOB_SPEC", spec, raising=False)
|
|
423
|
-
monkeypatch.setattr(W, "SEED", 42, raising=False)
|
|
424
|
-
monkeypatch.setattr(W, "THINKING", False, raising=False)
|
|
425
|
-
monkeypatch.setattr(W, "require_active_env", lambda: _Env(), raising=False)
|
|
426
|
-
monkeypatch.setattr(W, "grpo_overrides", lambda: {}, raising=False)
|
|
427
|
-
monkeypatch.setattr(W, "grpo_mask_truncated_completions", lambda train: False, raising=False)
|
|
428
|
-
monkeypatch.setattr(W, "load_tokenizer", lambda *args, **kwargs: _Tokenizer(), raising=False)
|
|
429
|
-
monkeypatch.setattr(rl_verl, "seed_training_rngs", lambda seed: None)
|
|
430
|
-
monkeypatch.setattr(rl_verl, "model_max_position_embeddings", lambda *a, **k: 32768)
|
|
431
|
-
return rl_verl._resolve_single_turn_inputs()
|
|
356
|
+
return _capability_resolve(monkeypatch, _capability_env(), train=train)
|
|
432
357
|
|
|
433
358
|
|
|
434
359
|
def test_save_freq_is_the_gcd_so_verl_lands_on_every_required_step(monkeypatch):
|
|
@@ -1343,3 +1268,119 @@ def test_train_notes_report_token_bounded_batching_as_unset_not_fabricated():
|
|
|
1343
1268
|
assert notes["ppo_max_token_len_per_gpu"] == 4096
|
|
1344
1269
|
# trl pins vllm's prefill batch because it hardcodes 4096; this path sets no such override.
|
|
1345
1270
|
assert notes["vllm_max_num_batched_tokens"] is None
|
|
1271
|
+
|
|
1272
|
+
|
|
1273
|
+
# ------------------- capability guards: the four specs verl grpo refuses -------------------
|
|
1274
|
+
# these four raises are the ONLY thing standing between a trl-supported job and a verl run that
|
|
1275
|
+
# trains on a different contract. they had no regression coverage: every resolver test above drives
|
|
1276
|
+
# the happy path, so deleting any guard left the suite green. each test below asserts one rejection
|
|
1277
|
+
# by its own message, because a bare pytest.raises(RuntimeError) passes on any of the ~20 other
|
|
1278
|
+
# raises in this resolver.
|
|
1279
|
+
|
|
1280
|
+
|
|
1281
|
+
def _capability_env(*, multi_turn=False, is_tool_env=False, images=False):
|
|
1282
|
+
"""a minimal single-turn text env, optionally flipped to a shape verl grpo rejects."""
|
|
1283
|
+
|
|
1284
|
+
class _Env:
|
|
1285
|
+
def __init__(self):
|
|
1286
|
+
self.multi_turn = multi_turn
|
|
1287
|
+
self.is_tool_env = is_tool_env
|
|
1288
|
+
|
|
1289
|
+
def dataset(self):
|
|
1290
|
+
return [{"index": i} for i in range(8)]
|
|
1291
|
+
|
|
1292
|
+
def prompt_messages(self, ex):
|
|
1293
|
+
if images:
|
|
1294
|
+
# record_has_images matches an image content BLOCK, so build the real shape rather
|
|
1295
|
+
# than a sentinel key the guard would not see.
|
|
1296
|
+
return [
|
|
1297
|
+
{
|
|
1298
|
+
"role": "user",
|
|
1299
|
+
"content": [
|
|
1300
|
+
{"type": "text", "text": f"question {ex['index']}"},
|
|
1301
|
+
{"type": "image_url", "image_url": {"url": "https://x/y.png"}},
|
|
1302
|
+
],
|
|
1303
|
+
}
|
|
1304
|
+
]
|
|
1305
|
+
return [{"role": "user", "content": f"question {ex['index']}"}]
|
|
1306
|
+
|
|
1307
|
+
return _Env()
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
def _capability_resolve(monkeypatch, env, train=None, overrides=None):
|
|
1311
|
+
"""run the resolver against one env, with everything else on the supported path."""
|
|
1312
|
+
from flash.engine.worker._pkg import W as _PkgW
|
|
1313
|
+
from flash.spec import JobSpec
|
|
1314
|
+
|
|
1315
|
+
class _Tokenizer:
|
|
1316
|
+
pad_token = None
|
|
1317
|
+
eos_token = "<eos>"
|
|
1318
|
+
|
|
1319
|
+
def apply_chat_template(self, messages, **kwargs):
|
|
1320
|
+
return "prompt"
|
|
1321
|
+
|
|
1322
|
+
def __call__(self, text, **kwargs):
|
|
1323
|
+
return SimpleNamespace(input_ids=[1])
|
|
1324
|
+
|
|
1325
|
+
spec = JobSpec.from_dict(
|
|
1326
|
+
{
|
|
1327
|
+
"model": "Qwen/Qwen3.5-0.8B",
|
|
1328
|
+
"algorithm": "grpo",
|
|
1329
|
+
"train": {"batch_size": 4, "epochs": 1, **(train or {})},
|
|
1330
|
+
}
|
|
1331
|
+
)
|
|
1332
|
+
monkeypatch.setattr(_PkgW, "JOB_SPEC", spec, raising=False)
|
|
1333
|
+
monkeypatch.setattr(_PkgW, "SEED", 42, raising=False)
|
|
1334
|
+
monkeypatch.setattr(_PkgW, "THINKING", False, raising=False)
|
|
1335
|
+
monkeypatch.setattr(_PkgW, "require_active_env", lambda: env, raising=False)
|
|
1336
|
+
monkeypatch.setattr(_PkgW, "grpo_overrides", lambda: dict(overrides or {}), raising=False)
|
|
1337
|
+
monkeypatch.setattr(_PkgW, "grpo_mask_truncated_completions", lambda t: False, raising=False)
|
|
1338
|
+
monkeypatch.setattr(_PkgW, "load_tokenizer", lambda *a, **k: _Tokenizer(), raising=False)
|
|
1339
|
+
monkeypatch.setattr(rl_verl, "seed_training_rngs", lambda seed: None)
|
|
1340
|
+
monkeypatch.setattr(rl_verl, "model_max_position_embeddings", lambda *a, **k: 32768)
|
|
1341
|
+
return rl_verl._resolve_single_turn_inputs()
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
def test_capability_guard_rejects_multi_turn_env(monkeypatch):
|
|
1345
|
+
# trl grpo drives multi-turn through a rollout func (rl.py select_grpo_trainer); the verl path
|
|
1346
|
+
# has no equivalent, so it must refuse rather than train only the first turn.
|
|
1347
|
+
with pytest.raises(RuntimeError, match="single-turn, non-tool"):
|
|
1348
|
+
_capability_resolve(monkeypatch, _capability_env(multi_turn=True))
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
def test_capability_guard_rejects_tool_env(monkeypatch):
|
|
1352
|
+
# trl grpo hands tool schemas AND callables to the trainer; verl gets neither, so a tool env
|
|
1353
|
+
# would train against completions that never call a tool.
|
|
1354
|
+
with pytest.raises(RuntimeError, match="single-turn, non-tool"):
|
|
1355
|
+
_capability_resolve(monkeypatch, _capability_env(is_tool_env=True))
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
def test_capability_guard_rejects_image_prompts(monkeypatch):
|
|
1359
|
+
# this guard runs AFTER prompt_messages is built, so it needs a real image content block, not a
|
|
1360
|
+
# flag. trl selects a multimodal trainer here; verl grpo is text-only and would silently drop
|
|
1361
|
+
# the image, training the model on the caption alone.
|
|
1362
|
+
with pytest.raises(RuntimeError, match="non-multimodal grpo only"):
|
|
1363
|
+
_capability_resolve(monkeypatch, _capability_env(images=True))
|
|
1364
|
+
|
|
1365
|
+
|
|
1366
|
+
def test_capability_guard_rejects_kl_anchored_warm_start(monkeypatch):
|
|
1367
|
+
# verl computes its kl reference with adapters DISABLED, so under init_from_adapter the
|
|
1368
|
+
# reference is the bare base model and the penalty drags the policy away from the sft start -
|
|
1369
|
+
# the opposite of what the knob asks for. must raise until verl can hold a reference adapter.
|
|
1370
|
+
# the kl coefficient arrives through grpo_overrides, so it must go through the helper: patching
|
|
1371
|
+
# it separately gets clobbered by the helper's own patch and the test then fails on the adapter
|
|
1372
|
+
# download instead, passing a bare raises() while proving nothing about this guard.
|
|
1373
|
+
with pytest.raises(RuntimeError, match="kl_penalty_coef"):
|
|
1374
|
+
_capability_resolve(
|
|
1375
|
+
monkeypatch,
|
|
1376
|
+
_capability_env(),
|
|
1377
|
+
train={"init_from_adapter": "org/some-sft-adapter"},
|
|
1378
|
+
overrides={"kl_penalty_coef": 0.1},
|
|
1379
|
+
)
|
|
1380
|
+
|
|
1381
|
+
|
|
1382
|
+
def test_capability_guards_admit_the_supported_single_turn_text_env(monkeypatch):
|
|
1383
|
+
# the control: with none of the four shapes present the resolver must run to completion, so a
|
|
1384
|
+
# guard that fires on every env would fail here instead of passing the four tests above.
|
|
1385
|
+
inp = _capability_resolve(monkeypatch, _capability_env())
|
|
1386
|
+
assert inp["max_prompt_len"] > 0
|