freesolo-flash-dev 1.0.3__tar.gz → 1.0.5__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.3 → freesolo_flash_dev-1.0.5}/Dockerfile.worker +1 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/PKG-INFO +4 -4
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/__init__.py +5 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/commands.py +16 -14
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/envpush.py +192 -54
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/render.py +76 -13
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/training_doc.py +11 -8
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/client/http.py +40 -17
- freesolo_flash_dev-1.0.5/flash/engine/multiturn_reward_scoring.py +73 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/multiturn_rollout.py +43 -35
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/__init__.py +6 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/adapter.py +68 -15
- freesolo_flash_dev-1.0.5/flash/engine/worker/grpo_multimodal.py +274 -0
- freesolo_flash_dev-1.0.5/flash/engine/worker/grpo_perturn_trainer.py +138 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/heartbeat.py +66 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/hf.py +342 -119
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/lora.py +14 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/opd.py +38 -7
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/opd_vllm.py +77 -14
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/rl.py +125 -2
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/sft.py +713 -134
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/teacher.py +111 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/adapter.py +74 -8
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/base.py +40 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_poll.py +5 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_worker.py +5 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/schema/__init__.py +37 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/schema/fields.py +23 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/serve/deploy.py +141 -34
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/auth.py +44 -19
- freesolo_flash_dev-1.0.5/flash/server/db.py +248 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/routes/meta.py +8 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/routes/serving.py +106 -37
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/spec.py +32 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/pyproject.toml +11 -8
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/conftest.py +2 -0
- freesolo_flash_dev-1.0.5/tests/test_async_uploads.py +448 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_checkpoints.py +15 -14
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_commands.py +100 -9
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_render_theme.py +108 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_client.py +58 -6
- freesolo_flash_dev-1.0.5/tests/test_client_stream_reads.py +109 -0
- freesolo_flash_dev-1.0.5/tests/test_deploy_latency.py +418 -0
- freesolo_flash_dev-1.0.5/tests/test_env_push.py +700 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_flash_worker.py +20 -36
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_grpo_params.py +1 -0
- freesolo_flash_dev-1.0.5/tests/test_grpo_perturn.py +431 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_health_liveness.py +6 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_kernel_fingerprint.py +18 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_multimodal_training.py +17 -0
- freesolo_flash_dev-1.0.5/tests/test_multiturn_per_turn_reward.py +379 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_multiturn_rollout.py +7 -3
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_multiturn_rollout_coverage.py +6 -2
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_multiturn_rollout_request_policy.py +2 -0
- freesolo_flash_dev-1.0.5/tests/test_named_reward_metrics.py +79 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_opd.py +168 -33
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_opd_vllm.py +142 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_resume_on_retry.py +2 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_serve.py +44 -9
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_server_api.py +156 -1
- freesolo_flash_dev-1.0.5/tests/test_server_auth_singleflight.py +82 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_server_db.py +238 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_serving_contract.py +21 -4
- freesolo_flash_dev-1.0.5/tests/test_sft_activation_shaping.py +140 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_sft_example_selection.py +15 -0
- freesolo_flash_dev-1.0.5/tests/test_sft_tokenize_cache.py +375 -0
- freesolo_flash_dev-1.0.5/tests/test_single_turn_multimodal_grpo.py +368 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_spec_and_validation.py +91 -2
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_training_controls.py +2 -0
- freesolo_flash_dev-1.0.5/tests/test_warmstart_adapter_download.py +282 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_warmstart_cross_repo.py +15 -1
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_worker_init_heartbeat.py +49 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/uv.lock +4 -4
- freesolo_flash_dev-1.0.3/flash/server/db.py +0 -134
- freesolo_flash_dev-1.0.3/tests/test_env_push.py +0 -372
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.claude/skills/verify/SKILL.md +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.env.example +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/Dockerfile +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/README.md +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/_logging.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/catalog.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cli/env_setup.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/multimodal.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/preload.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_b200_rollout_opt.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_grpo_sleep_gate.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_multiturn_image_rollout.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_multiturn_rollout_records.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_opd_full_state_resume.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.0.3 → freesolo_flash_dev-1.0.5}/tests/test_worker_thinking.py +0 -0
|
@@ -55,7 +55,7 @@ RUN pip install --no-cache-dir \
|
|
|
55
55
|
"flashinfer-python==0.6.6" \
|
|
56
56
|
"bitsandbytes>=0.49" \
|
|
57
57
|
"datasets>=4.7,<6" \
|
|
58
|
-
"huggingface_hub>=0
|
|
58
|
+
"huggingface_hub>=1.2.0" \
|
|
59
59
|
"accelerate>=1.4" \
|
|
60
60
|
"wandb>=0.17" \
|
|
61
61
|
"flash-linear-attention @ git+https://github.com/fla-org/flash-linear-attention.git@f0e213dbd8b5fb90c3c7eca869ac1706d5377139" \
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
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
|
|
@@ -20,7 +20,7 @@ Requires-Dist: datasets>=2.19; extra == 'dev'
|
|
|
20
20
|
Requires-Dist: fastapi; extra == 'dev'
|
|
21
21
|
Requires-Dist: freesolo>=0.2.54; extra == 'dev'
|
|
22
22
|
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
23
|
-
Requires-Dist: huggingface-hub>=0
|
|
23
|
+
Requires-Dist: huggingface-hub>=1.2.0; extra == 'dev'
|
|
24
24
|
Requires-Dist: jsonschema>=4.23; extra == 'dev'
|
|
25
25
|
Requires-Dist: mypy>=1.13.0; extra == 'dev'
|
|
26
26
|
Requires-Dist: pytest>=9.0.3; extra == 'dev'
|
|
@@ -35,7 +35,7 @@ Requires-Dist: accelerate>=1.4; extra == 'gpu'
|
|
|
35
35
|
Requires-Dist: bitsandbytes>=0.49; extra == 'gpu'
|
|
36
36
|
Requires-Dist: datasets>=2.19; extra == 'gpu'
|
|
37
37
|
Requires-Dist: freesolo>=0.2.54; extra == 'gpu'
|
|
38
|
-
Requires-Dist: huggingface-hub>=0
|
|
38
|
+
Requires-Dist: huggingface-hub>=1.2.0; extra == 'gpu'
|
|
39
39
|
Requires-Dist: peft>=0.19; extra == 'gpu'
|
|
40
40
|
Requires-Dist: torch==2.10.0; extra == 'gpu'
|
|
41
41
|
Requires-Dist: transformers<5.11,>=5.6; extra == 'gpu'
|
|
@@ -46,7 +46,7 @@ Requires-Dist: datasets>=2.19; extra == 'server'
|
|
|
46
46
|
Requires-Dist: fastapi; extra == 'server'
|
|
47
47
|
Requires-Dist: freesolo>=0.2.54; extra == 'server'
|
|
48
48
|
Requires-Dist: httpx>=0.27; extra == 'server'
|
|
49
|
-
Requires-Dist: huggingface-hub>=0
|
|
49
|
+
Requires-Dist: huggingface-hub>=1.2.0; extra == 'server'
|
|
50
50
|
Requires-Dist: jsonschema>=4.23; extra == 'server'
|
|
51
51
|
Requires-Dist: referencing>=0.28.4; extra == 'server'
|
|
52
52
|
Requires-Dist: regex>=2024.11.6; extra == 'server'
|
|
@@ -424,7 +424,11 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
424
424
|
deployments.set_defaults(func=cmd_deployments)
|
|
425
425
|
|
|
426
426
|
chat = sub.add_parser("chat", help="chat with a deployed adapter")
|
|
427
|
-
chat.add_argument(
|
|
427
|
+
chat.add_argument(
|
|
428
|
+
"run_id",
|
|
429
|
+
help="a bare RUN_ID (its current deployment), RUN_ID/step-N (a specific deployed "
|
|
430
|
+
"checkpoint), or a full immutable adapter revision",
|
|
431
|
+
)
|
|
428
432
|
chat.add_argument("-m", "--message", required=True)
|
|
429
433
|
chat.add_argument(
|
|
430
434
|
"--system",
|
|
@@ -160,8 +160,9 @@ def cmd_gpus(args) -> int:
|
|
|
160
160
|
(info for info in GPU_INFO.values() if info.enum_member), key=lambda g: g.hourly_usd
|
|
161
161
|
)
|
|
162
162
|
tip = (
|
|
163
|
-
"Tip: GPU
|
|
164
|
-
"cheapest validated
|
|
163
|
+
"Tip: GPU allocation is automatic by default.\n"
|
|
164
|
+
"The allocator picks the cheapest validated class that fits. Pin a specific class by "
|
|
165
|
+
'adding exact_type = "<CLASS>" to the [gpu] section.'
|
|
165
166
|
)
|
|
166
167
|
if render.styled():
|
|
167
168
|
rows = [(info.name, info.vram_gb, runpod_rates.get(info.name)) for info in infos]
|
|
@@ -383,18 +384,26 @@ def _log_follow_progress(status: dict | None, fallback_state: str) -> tuple[str,
|
|
|
383
384
|
parts = [state]
|
|
384
385
|
heartbeat = status.get("last_heartbeat") if isinstance(status, dict) else None
|
|
385
386
|
if isinstance(heartbeat, dict):
|
|
387
|
+
heartbeat_age_seconds = render._heartbeat_age_seconds(heartbeat.get("ts"))
|
|
386
388
|
stage = heartbeat.get("stage")
|
|
387
389
|
if stage:
|
|
388
390
|
parts.append(f"stage={stage}")
|
|
391
|
+
if state == "running":
|
|
392
|
+
warmup = render.warmup_message(
|
|
393
|
+
stage,
|
|
394
|
+
heartbeat_age_seconds,
|
|
395
|
+
render.heartbeat_is_current_attempt(status, heartbeat),
|
|
396
|
+
)
|
|
397
|
+
if warmup:
|
|
398
|
+
parts.append(warmup)
|
|
389
399
|
step = heartbeat.get("step")
|
|
390
400
|
if step is not None:
|
|
391
401
|
parts.append(f"step={step}")
|
|
392
402
|
# live heartbeat age so a long quiet phase reads as "alive, throttled" not "frozen".
|
|
393
403
|
# minute granularity: the non-TTY follow path prints a line whenever this string changes,
|
|
394
404
|
# so a seconds-precision age would emit one line per poll.
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
mins = int(max(0.0, time.time() - ts) // 60)
|
|
405
|
+
if heartbeat_age_seconds is not None:
|
|
406
|
+
mins = int(heartbeat_age_seconds // 60)
|
|
398
407
|
parts.append(f"hb={mins}m" if mins else "hb=<1m")
|
|
399
408
|
realized = status.get("realized_cost_usd")
|
|
400
409
|
if realized is not None:
|
|
@@ -737,18 +746,11 @@ def cmd_chat(args) -> int:
|
|
|
737
746
|
if revision is None and parsed is None:
|
|
738
747
|
print(
|
|
739
748
|
f"invalid chat target {args.run_id!r} "
|
|
740
|
-
"(expected a bare <run_id
|
|
741
|
-
file=sys.stderr,
|
|
742
|
-
)
|
|
743
|
-
return 1
|
|
744
|
-
if revision is None and parsed[1] is not None:
|
|
745
|
-
print(
|
|
746
|
-
"RUN_ID/step-N is not a valid chat target because it would route through the mutable "
|
|
747
|
-
"run alias; use the full immutable adapter revision returned by `flash deployments`",
|
|
749
|
+
"(expected a bare <run_id>, <run_id>/step-N, or full immutable adapter revision)",
|
|
748
750
|
file=sys.stderr,
|
|
749
751
|
)
|
|
750
752
|
return 1
|
|
751
|
-
chat_target = args.run_id
|
|
753
|
+
chat_target = args.run_id
|
|
752
754
|
client = client_from_config()
|
|
753
755
|
messages = [{"role": "user", "content": args.message}]
|
|
754
756
|
system = getattr(args, "system", None)
|
|
@@ -11,6 +11,7 @@ import os
|
|
|
11
11
|
import re
|
|
12
12
|
import sys
|
|
13
13
|
import tempfile
|
|
14
|
+
from collections.abc import Iterator
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
from typing import TYPE_CHECKING, Literal, TypeAlias
|
|
16
17
|
|
|
@@ -174,6 +175,10 @@ def cmd_env_delete(args) -> int:
|
|
|
174
175
|
|
|
175
176
|
|
|
176
177
|
_ENV_ENTRYPOINT = "environment.py"
|
|
178
|
+
_ENV_SYSPATH_BOOTSTRAP = (
|
|
179
|
+
"import os as _flash_os, sys as _flash_sys\n"
|
|
180
|
+
"_flash_sys.path.insert(0, _flash_os.path.dirname(__file__))\n"
|
|
181
|
+
)
|
|
177
182
|
_ENV_PUSH_IGNORED_NAMES = frozenset(
|
|
178
183
|
{
|
|
179
184
|
".prime",
|
|
@@ -183,26 +188,47 @@ _ENV_PUSH_IGNORED_NAMES = frozenset(
|
|
|
183
188
|
".venv",
|
|
184
189
|
".mypy_cache",
|
|
185
190
|
".pytest_cache",
|
|
186
|
-
"
|
|
187
|
-
"
|
|
191
|
+
".ruff_cache",
|
|
192
|
+
".idea",
|
|
193
|
+
".vscode",
|
|
194
|
+
".ds_store",
|
|
195
|
+
".git-worktrees",
|
|
196
|
+
".env",
|
|
197
|
+
".netrc",
|
|
198
|
+
".aws",
|
|
199
|
+
".ssh",
|
|
200
|
+
"venv",
|
|
201
|
+
"node_modules",
|
|
202
|
+
"credentials",
|
|
203
|
+
"secrets",
|
|
188
204
|
}
|
|
189
205
|
)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
".yml",
|
|
204
|
-
}
|
|
206
|
+
_ENV_PUSH_ROOT_IGNORED_NAMES = frozenset({"pyproject.toml", "source"})
|
|
207
|
+
_ENV_PUSH_SECRET_PATTERNS = (
|
|
208
|
+
".env.*",
|
|
209
|
+
"*.env",
|
|
210
|
+
"*.pem",
|
|
211
|
+
"*.key",
|
|
212
|
+
"*.pfx",
|
|
213
|
+
"*.p12",
|
|
214
|
+
"credentials*",
|
|
215
|
+
"id_rsa*",
|
|
216
|
+
"id_dsa*",
|
|
217
|
+
"id_ecdsa*",
|
|
218
|
+
"id_ed25519*",
|
|
205
219
|
)
|
|
220
|
+
# secret patterns match secret data FILES only (see _ignore_env_push_path): they never prune a
|
|
221
|
+
# directory, so a package tree like credentials_store/ still ships, and python source is exempt,
|
|
222
|
+
# so helper modules like credentials.py or id_ed25519_loader.py travel instead of being silently
|
|
223
|
+
# dropped and breaking the worker with ModuleNotFoundError. that keeps the prefixes broad enough
|
|
224
|
+
# to catch backup variants (credentials_backup, id_rsa_backup) without eating code or packages.
|
|
225
|
+
_ENV_PUSH_CODE_SUFFIXES = frozenset({".py", ".pyi"})
|
|
226
|
+
_ENV_PUSH_MAX_TOTAL_BYTES = 256 * 1024 * 1024
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
from flash.envs.archive_policy import ARCHIVE_MEMBER_LIMIT as _ENV_PUSH_MAX_FILES
|
|
230
|
+
except ImportError:
|
|
231
|
+
_ENV_PUSH_MAX_FILES = 5000
|
|
206
232
|
|
|
207
233
|
|
|
208
234
|
def _normalize_env_name(raw: str) -> str | None:
|
|
@@ -227,16 +253,12 @@ def _normalize_env_name(raw: str) -> str | None:
|
|
|
227
253
|
|
|
228
254
|
def _with_syspath_bootstrap(env_source: str) -> str:
|
|
229
255
|
"""Prepend a sys.path bootstrap so a published env can resolve shipped sibling helpers."""
|
|
230
|
-
bootstrap = (
|
|
231
|
-
"import os as _flash_os, sys as _flash_sys\n"
|
|
232
|
-
"_flash_sys.path.insert(0, _flash_os.path.dirname(__file__))\n"
|
|
233
|
-
)
|
|
234
256
|
import ast
|
|
235
257
|
|
|
236
258
|
try:
|
|
237
259
|
tree = ast.parse(env_source)
|
|
238
260
|
except SyntaxError:
|
|
239
|
-
return
|
|
261
|
+
return _ENV_SYSPATH_BOOTSTRAP + env_source
|
|
240
262
|
insert_after = 0
|
|
241
263
|
body = tree.body
|
|
242
264
|
i = 0
|
|
@@ -252,7 +274,16 @@ def _with_syspath_bootstrap(env_source: str) -> str:
|
|
|
252
274
|
insert_after = body[i].end_lineno or insert_after
|
|
253
275
|
i += 1
|
|
254
276
|
lines = env_source.splitlines(keepends=True)
|
|
255
|
-
return
|
|
277
|
+
return (
|
|
278
|
+
"".join(lines[:insert_after])
|
|
279
|
+
+ _ENV_SYSPATH_BOOTSTRAP
|
|
280
|
+
+ "".join(lines[insert_after:])
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _raise_walk_error(error: OSError) -> None:
|
|
285
|
+
"""fail env packaging loudly instead of silently skipping an unreadable directory."""
|
|
286
|
+
raise error
|
|
256
287
|
|
|
257
288
|
|
|
258
289
|
def _tar_b64(directory: Path) -> str:
|
|
@@ -266,44 +297,130 @@ def _tar_b64(directory: Path) -> str:
|
|
|
266
297
|
with tarfile.open(fileobj=buf, mode="w:gz") as tar:
|
|
267
298
|
for root, dirs, files in os.walk(directory):
|
|
268
299
|
root_path = Path(root)
|
|
269
|
-
dirs[:] = sorted(d for d in dirs if d not in _ENV_PUSH_IGNORED_NAMES)
|
|
270
|
-
for name in dirs:
|
|
271
|
-
child = root_path / name
|
|
272
|
-
tar.add(child, arcname=str(child.relative_to(directory)), recursive=False)
|
|
300
|
+
dirs[:] = sorted(d for d in dirs if d.lower() not in _ENV_PUSH_IGNORED_NAMES)
|
|
273
301
|
for name in sorted(files):
|
|
274
302
|
child = root_path / name
|
|
275
303
|
tar.add(child, arcname=str(child.relative_to(directory)), recursive=False)
|
|
276
304
|
return base64.b64encode(buf.getvalue()).decode()
|
|
277
305
|
|
|
278
306
|
|
|
279
|
-
def
|
|
280
|
-
"""
|
|
281
|
-
import
|
|
307
|
+
def _ignore_env_push_path(path: Path, *, env_root: Path, entrypoint: Path) -> bool:
|
|
308
|
+
"""Return whether a source path must not be included in an env package."""
|
|
309
|
+
import fnmatch
|
|
310
|
+
|
|
311
|
+
name = path.name
|
|
312
|
+
lowered_name = name.lower()
|
|
313
|
+
if path.is_symlink():
|
|
314
|
+
return True
|
|
315
|
+
if path.is_dir() and (path / "pyvenv.cfg").is_file():
|
|
316
|
+
return True
|
|
317
|
+
if path == entrypoint or (
|
|
318
|
+
path.parent == env_root and lowered_name == _ENV_ENTRYPOINT.lower()
|
|
319
|
+
):
|
|
320
|
+
return True
|
|
321
|
+
if lowered_name.startswith(".") or lowered_name in _ENV_PUSH_IGNORED_NAMES:
|
|
322
|
+
return True
|
|
323
|
+
if path.parent == env_root and lowered_name in _ENV_PUSH_ROOT_IGNORED_NAMES:
|
|
324
|
+
return True
|
|
325
|
+
if (
|
|
326
|
+
path.is_file()
|
|
327
|
+
and path.suffix.lower() not in _ENV_PUSH_CODE_SUFFIXES
|
|
328
|
+
and any(fnmatch.fnmatchcase(lowered_name, pattern) for pattern in _ENV_PUSH_SECRET_PATTERNS)
|
|
329
|
+
):
|
|
330
|
+
return True
|
|
331
|
+
return not (path.is_dir() or path.is_file())
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _iter_env_sidecar_files(
|
|
335
|
+
env_root: Path, *, entrypoint: Path, include_full_tree: bool
|
|
336
|
+
) -> Iterator[tuple[Path, Path]]:
|
|
337
|
+
"""Yield publishable sidecar files and their package-relative paths."""
|
|
338
|
+
import os
|
|
282
339
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
340
|
+
roots = [env_root]
|
|
341
|
+
if not include_full_tree:
|
|
342
|
+
# a single-file push carries only the entrypoint, its dataset sidecars, and its own
|
|
343
|
+
# docs. ship user-authored docs so the synthesized stub readme does not stand in for
|
|
344
|
+
# real training guidance the user shipped next to the module.
|
|
345
|
+
for doc_name in ("README.md", "TRAINING.md"):
|
|
346
|
+
doc = env_root / doc_name
|
|
347
|
+
if doc.is_file() and not _ignore_env_push_path(
|
|
348
|
+
doc, env_root=env_root, entrypoint=entrypoint
|
|
349
|
+
):
|
|
350
|
+
yield doc, doc.relative_to(env_root)
|
|
351
|
+
roots = [
|
|
352
|
+
env_root / name
|
|
353
|
+
for name in ("dataset", "datasets")
|
|
354
|
+
if (env_root / name).is_dir() and not (env_root / name).is_symlink()
|
|
355
|
+
]
|
|
356
|
+
|
|
357
|
+
for walk_root in roots:
|
|
358
|
+
for root, dirs, files in os.walk(
|
|
359
|
+
walk_root, topdown=True, followlinks=False, onerror=_raise_walk_error
|
|
288
360
|
):
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
shutil.copytree(
|
|
296
|
-
child,
|
|
297
|
-
target,
|
|
298
|
-
ignore=shutil.ignore_patterns(*_ENV_PUSH_IGNORED_NAMES),
|
|
361
|
+
root_path = Path(root)
|
|
362
|
+
dirs[:] = sorted(
|
|
363
|
+
name
|
|
364
|
+
for name in dirs
|
|
365
|
+
if not _ignore_env_push_path(
|
|
366
|
+
root_path / name, env_root=env_root, entrypoint=entrypoint
|
|
299
367
|
)
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
368
|
+
)
|
|
369
|
+
for name in sorted(files):
|
|
370
|
+
child = root_path / name
|
|
371
|
+
if _ignore_env_push_path(child, env_root=env_root, entrypoint=entrypoint):
|
|
372
|
+
continue
|
|
373
|
+
yield child, child.relative_to(env_root)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _check_env_push_limits(
|
|
377
|
+
env_root: Path, *, entrypoint: Path, include_full_tree: bool, env_name: str
|
|
378
|
+
) -> None:
|
|
379
|
+
"""Reject oversized source trees before copying or building an in-memory archive."""
|
|
380
|
+
files = 1
|
|
381
|
+
total_bytes = entrypoint.stat().st_size + len(_ENV_SYSPATH_BOOTSTRAP.encode())
|
|
382
|
+
directories: set[Path] = set()
|
|
383
|
+
has_readme = False
|
|
384
|
+
for child, relative in _iter_env_sidecar_files(
|
|
385
|
+
env_root, entrypoint=entrypoint, include_full_tree=include_full_tree
|
|
386
|
+
):
|
|
387
|
+
files += 1
|
|
388
|
+
total_bytes += child.stat().st_size
|
|
389
|
+
has_readme = has_readme or relative == Path("README.md")
|
|
390
|
+
# the server counts every file AND directory against the same member cap when it
|
|
391
|
+
# repackages the checkout for download, so count unique parent dirs here too.
|
|
392
|
+
directories.update(parent for parent in relative.parents if parent != Path("."))
|
|
393
|
+
if not has_readme:
|
|
394
|
+
files += 1
|
|
395
|
+
total_bytes += len(f"# {env_name}\n\nFlash Freesolo environment.\n".encode())
|
|
396
|
+
|
|
397
|
+
members = files + len(directories)
|
|
398
|
+
if total_bytes > _ENV_PUSH_MAX_TOTAL_BYTES:
|
|
399
|
+
raise ValueError(
|
|
400
|
+
f"environment package totals {_human_bytes(total_bytes)} "
|
|
401
|
+
f"(limit {_human_bytes(_ENV_PUSH_MAX_TOTAL_BYTES)}); "
|
|
402
|
+
"remove large artifacts or use a smaller dataset"
|
|
403
|
+
)
|
|
404
|
+
if members > _ENV_PUSH_MAX_FILES:
|
|
405
|
+
raise ValueError(
|
|
406
|
+
f"selected environment contains {members:,} files and directories "
|
|
407
|
+
f"(limit {_ENV_PUSH_MAX_FILES:,}); "
|
|
408
|
+
"remove large artifacts or use a smaller dataset"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _copy_env_sidecars(
|
|
413
|
+
env_root: Path, dest: Path, *, entrypoint: Path, include_full_tree: bool
|
|
414
|
+
) -> None:
|
|
415
|
+
"""Copy publishable sidecar files beside environment.py, creating directories lazily."""
|
|
416
|
+
import shutil
|
|
417
|
+
|
|
418
|
+
for child, relative in _iter_env_sidecar_files(
|
|
419
|
+
env_root, entrypoint=entrypoint, include_full_tree=include_full_tree
|
|
420
|
+
):
|
|
421
|
+
target = dest / relative
|
|
422
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
423
|
+
shutil.copy2(child, target)
|
|
307
424
|
|
|
308
425
|
|
|
309
426
|
def _human_bytes(n: int) -> str:
|
|
@@ -385,8 +502,11 @@ def cmd_env_push(args) -> int:
|
|
|
385
502
|
src = Path(args.path)
|
|
386
503
|
if not src.exists():
|
|
387
504
|
return _err(f"no such path: {src}")
|
|
505
|
+
if src.is_symlink():
|
|
506
|
+
return _err(f"cannot publish {src}: symlinks are not allowed")
|
|
388
507
|
|
|
389
|
-
|
|
508
|
+
include_full_tree = src.is_dir()
|
|
509
|
+
if include_full_tree:
|
|
390
510
|
canonical_entrypoint = src / _ENV_ENTRYPOINT
|
|
391
511
|
if canonical_entrypoint.is_file():
|
|
392
512
|
entrypoint = canonical_entrypoint
|
|
@@ -410,11 +530,29 @@ def cmd_env_push(args) -> int:
|
|
|
410
530
|
else:
|
|
411
531
|
return _err(f"cannot publish {src}: expected a Freesolo .py module or an env directory.")
|
|
412
532
|
|
|
533
|
+
if entrypoint.is_symlink():
|
|
534
|
+
return _err(f"cannot publish {entrypoint}: symlinks are not allowed")
|
|
535
|
+
|
|
536
|
+
try:
|
|
537
|
+
_check_env_push_limits(
|
|
538
|
+
env_root,
|
|
539
|
+
entrypoint=entrypoint,
|
|
540
|
+
include_full_tree=include_full_tree,
|
|
541
|
+
env_name=env_name,
|
|
542
|
+
)
|
|
543
|
+
except (OSError, ValueError) as exc:
|
|
544
|
+
return _err(f"cannot publish {src}: {exc}")
|
|
545
|
+
|
|
413
546
|
with tempfile.TemporaryDirectory(prefix="flash-env-push-") as tmp:
|
|
414
547
|
pkg = Path(tmp)
|
|
415
548
|
module_source = entrypoint.read_text()
|
|
416
549
|
(pkg / _ENV_ENTRYPOINT).write_text(_with_syspath_bootstrap(module_source))
|
|
417
|
-
_copy_env_sidecars(
|
|
550
|
+
_copy_env_sidecars(
|
|
551
|
+
env_root,
|
|
552
|
+
pkg,
|
|
553
|
+
entrypoint=entrypoint,
|
|
554
|
+
include_full_tree=include_full_tree,
|
|
555
|
+
)
|
|
418
556
|
# Only synthesize a stub README when the env didn't ship its own (now carried as a
|
|
419
557
|
# ``.md`` sidecar) — don't clobber a user-authored README with boilerplate.
|
|
420
558
|
readme = pkg / "README.md"
|
|
@@ -533,21 +533,76 @@ def _humanize_ts(value) -> str | None:
|
|
|
533
533
|
return datetime.datetime.fromtimestamp(value, datetime.UTC).strftime("%Y-%m-%d %H:%M UTC")
|
|
534
534
|
|
|
535
535
|
|
|
536
|
-
def
|
|
537
|
-
"""
|
|
536
|
+
def _heartbeat_age_seconds(value: object) -> float | None:
|
|
537
|
+
"""Return heartbeat age in seconds, or None for an unusable timestamp."""
|
|
538
538
|
if not isinstance(value, (int, float)) or value <= 0:
|
|
539
539
|
return None
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
540
|
+
return max(0.0, time.time() - value)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def _humanize_age_seconds(seconds: float | None) -> str | None:
|
|
544
|
+
if seconds is None:
|
|
545
|
+
return None
|
|
546
|
+
if seconds < 90:
|
|
547
|
+
return f"{int(seconds)}s ago"
|
|
548
|
+
if seconds < 5400:
|
|
549
|
+
return f"{int(seconds // 60)}m ago"
|
|
550
|
+
return f"{seconds / 3600:.1f}h ago"
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def _humanize_age(value) -> str | None:
|
|
554
|
+
"""Format an epoch seconds value as a compact age ("3m ago"), None for non-numbers."""
|
|
555
|
+
return _humanize_age_seconds(_heartbeat_age_seconds(value))
|
|
546
556
|
|
|
547
557
|
|
|
548
558
|
# heartbeat age past which the panel reminds that quiet is normal: worker uploads are throttled
|
|
549
|
-
# (240s quiet phases, up to 900s mid-training), so a frozen ts is usually
|
|
559
|
+
# (240s quiet phases, up to 900s mid-training), so a frozen ts is usually not a dead worker.
|
|
550
560
|
_HB_QUIET_HINT_AFTER_S = 300.0
|
|
561
|
+
_WARMUP_HEARTBEAT_FRESH_FOR_S = 1200.0
|
|
562
|
+
_WARMUP_STAGES = frozenset({"rl_train_start", "rl_initializing"})
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def heartbeat_is_current_attempt(obj: dict, heartbeat: dict) -> bool:
|
|
566
|
+
"""False only when the heartbeat provably belongs to a superseded retry attempt.
|
|
567
|
+
|
|
568
|
+
Retries reuse the seed's heartbeat path, so a recovered run flips back to ``running`` for the
|
|
569
|
+
replacement worker while ``last_heartbeat`` can still be the previous attempt's setup ping until
|
|
570
|
+
the new worker publishes one. ``remote.attempt`` is the live attempt; ``last_heartbeat.attempt``
|
|
571
|
+
is the one that produced the ping. When the live attempt is known, keep the reassurance only for a
|
|
572
|
+
heartbeat whose attempt matches it. When it is unknown (e.g. a managed status payload that omits
|
|
573
|
+
``remote``), fall back to ``warmup_message``'s age gating rather than suppress, so warmup still
|
|
574
|
+
reassures on planes that do not surface a live attempt.
|
|
575
|
+
"""
|
|
576
|
+
# reuse the poller's attempt-identity contract (a bounded nonnegative int, never a bool, string,
|
|
577
|
+
# or float) so the status display and stall detection agree on what a valid attempt is.
|
|
578
|
+
from flash.providers._poll import _attempt_int
|
|
579
|
+
|
|
580
|
+
remote = obj.get("remote")
|
|
581
|
+
current_attempt = _attempt_int(remote.get("attempt")) if isinstance(remote, dict) else None
|
|
582
|
+
if current_attempt is None:
|
|
583
|
+
return True
|
|
584
|
+
return _attempt_int(heartbeat.get("attempt")) == current_attempt
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def warmup_message(
|
|
588
|
+
stage: object,
|
|
589
|
+
heartbeat_age_seconds: float | None,
|
|
590
|
+
from_current_attempt: bool = True,
|
|
591
|
+
) -> str | None:
|
|
592
|
+
"""Explain healthy RL setup stages only while the heartbeat is fresh and from the live attempt."""
|
|
593
|
+
stage_name = str(stage)
|
|
594
|
+
if stage_name not in _WARMUP_STAGES:
|
|
595
|
+
return None
|
|
596
|
+
if not from_current_attempt:
|
|
597
|
+
return None
|
|
598
|
+
if heartbeat_age_seconds is None:
|
|
599
|
+
return None
|
|
600
|
+
if heartbeat_age_seconds > _WARMUP_HEARTBEAT_FRESH_FOR_S:
|
|
601
|
+
return None
|
|
602
|
+
return (
|
|
603
|
+
f"warming up (stage={stage_name}): initializing model, vLLM, and training kernels - "
|
|
604
|
+
"typically several minutes, sometimes 15-20 min; setup is not billed; do not cancel"
|
|
605
|
+
)
|
|
551
606
|
|
|
552
607
|
|
|
553
608
|
def _heartbeat_pairs(obj: dict) -> list[tuple[str, str]]:
|
|
@@ -562,11 +617,19 @@ def _heartbeat_pairs(obj: dict) -> list[tuple[str, str]]:
|
|
|
562
617
|
if hb.get("liveness"):
|
|
563
618
|
worker += " · alive ping"
|
|
564
619
|
pairs = [("worker", worker)]
|
|
565
|
-
|
|
566
|
-
|
|
620
|
+
heartbeat_age_seconds = _heartbeat_age_seconds(hb.get("ts"))
|
|
621
|
+
running = str(obj.get("state") or "") == "running"
|
|
622
|
+
if running:
|
|
623
|
+
warmup = warmup_message(
|
|
624
|
+
hb.get("stage"),
|
|
625
|
+
heartbeat_age_seconds,
|
|
626
|
+
heartbeat_is_current_attempt(obj, hb),
|
|
627
|
+
)
|
|
628
|
+
if warmup:
|
|
629
|
+
pairs.append(("warmup", warmup))
|
|
630
|
+
age = _humanize_age_seconds(heartbeat_age_seconds)
|
|
567
631
|
if age:
|
|
568
|
-
running
|
|
569
|
-
if running and isinstance(ts, (int, float)) and (time.time() - ts) > _HB_QUIET_HINT_AFTER_S:
|
|
632
|
+
if running and heartbeat_age_seconds > _HB_QUIET_HINT_AFTER_S:
|
|
570
633
|
age += _dim(
|
|
571
634
|
" (heartbeat uploads are throttled; quiet is not dead - check flash log -f <run-id>)"
|
|
572
635
|
)
|
|
@@ -109,6 +109,8 @@ epochs = 1 # one pass over the retained train rows
|
|
|
109
109
|
max_examples = 2 # rows to train on (the starter dataset has 2)
|
|
110
110
|
# max_steps = 100 # positive values set the exact optimizer-update horizon
|
|
111
111
|
# save_at_steps = [10, 50, 100] # requires max_steps; overrides save_every
|
|
112
|
+
# multi-turn GRPO defaults to one reward per rollout; choose "per_turn" for turn-level credit.
|
|
113
|
+
# credit_assignment = "per_episode"
|
|
112
114
|
lora_rank = 32
|
|
113
115
|
lora_alpha = 64
|
|
114
116
|
# All SFT/GRPO knobs live under [train]. Do not add [sft] or [grpo] tables.
|
|
@@ -339,10 +341,12 @@ def score_response(self, example, response_text) -> RewardResult:
|
|
|
339
341
|
)
|
|
340
342
|
```
|
|
341
343
|
|
|
342
|
-
`score` is what GRPO optimizes (it becomes the run's `total`).
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
344
|
+
`score` is what GRPO optimizes (it becomes the run's `total`). In standard (single-turn)
|
|
345
|
+
GRPO, each `RewardMetric` is averaged across scored completions and logged by name at
|
|
346
|
+
the managed heartbeat cadence, which is not guaranteed to be every optimizer step. That
|
|
347
|
+
is how the clean success rate becomes visible. Multi-turn scoring currently reports only
|
|
348
|
+
the scalar reward. Use the shaped `score` to confirm the model is learning *at all*, and
|
|
349
|
+
judge the run on the explicit `success` metric.
|
|
346
350
|
|
|
347
351
|
When `thinking = true`, score the final answer unless you intentionally need the
|
|
348
352
|
reasoning trace. Flash passes a string-compatible response object to `score_response`;
|
|
@@ -550,10 +554,9 @@ every run, the last two matter more the smaller the model:
|
|
|
550
554
|
frontier one outright; a frontier `teacher_model` only earns its keep once the student is large
|
|
551
555
|
enough to track it (~9B+). Early-stopping also largely neutralizes this gap, since the teacher-driven
|
|
552
556
|
over-sharpening only compounds over many steps.
|
|
553
|
-
- **Diagnose it
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
and compare an early checkpoint against the final one to watch the loop emerge over steps.
|
|
557
|
+
- **Diagnose it at serving.** Evaluate at **temperature=0** and flag
|
|
558
|
+
`finish_reason=length` completions that never emit your answer token. Compare an early checkpoint
|
|
559
|
+
against the final one to watch the loop emerge over steps.
|
|
557
560
|
|
|
558
561
|
### Distilling from base with no format anchor
|
|
559
562
|
|