synth-ai 0.2.9.dev0__py3-none-any.whl → 0.2.23.dev3__py3-none-any.whl
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.
- examples/README.md +1 -0
- examples/__init__.py +16 -0
- examples/analyze_semantic_words.sh +17 -0
- examples/baseline/banking77_baseline.py +243 -0
- examples/baseline/banking77_pipeline_baseline.py +294 -0
- examples/baseline/crafter_baseline.py +407 -0
- examples/baseline/pokemon_red_baseline.py +326 -0
- examples/baseline/simple_baseline.py +56 -0
- examples/baseline/warming_up_to_rl_baseline.py +239 -0
- examples/blog_posts/gepa/README.md +355 -0
- examples/blog_posts/gepa/configs/banking77_gepa_local.toml +95 -0
- examples/blog_posts/gepa/configs/banking77_gepa_test.toml +80 -0
- examples/blog_posts/gepa/configs/banking77_mipro_local.toml +50 -0
- examples/blog_posts/gepa/configs/banking77_pipeline_gepa_local.toml +101 -0
- examples/blog_posts/gepa/configs/banking77_pipeline_gepa_test.toml +96 -0
- examples/blog_posts/gepa/configs/hotpotqa_gepa_local.toml +57 -0
- examples/blog_posts/gepa/configs/hotpotqa_gepa_qwen.toml +35 -0
- examples/blog_posts/gepa/configs/hotpotqa_mipro_local.toml +51 -0
- examples/blog_posts/gepa/configs/hover_gepa_local.toml +57 -0
- examples/blog_posts/gepa/configs/hover_gepa_qwen.toml +35 -0
- examples/blog_posts/gepa/configs/hover_mipro_local.toml +51 -0
- examples/blog_posts/gepa/configs/ifbench_gepa_local.toml +57 -0
- examples/blog_posts/gepa/configs/ifbench_gepa_qwen.toml +35 -0
- examples/blog_posts/gepa/configs/ifbench_mipro_local.toml +51 -0
- examples/blog_posts/gepa/configs/pupa_gepa_local.toml +58 -0
- examples/blog_posts/gepa/configs/pupa_mipro_local.toml +52 -0
- examples/blog_posts/gepa/deploy_banking77_task_app.sh +54 -0
- examples/blog_posts/gepa/gepa_baseline.py +204 -0
- examples/blog_posts/gepa/query_prompts_example.py +97 -0
- examples/blog_posts/gepa/run_gepa_banking77.sh +112 -0
- examples/blog_posts/gepa/run_gepa_banking77_pipeline.sh +163 -0
- examples/blog_posts/gepa/task_apps.py +105 -0
- examples/blog_posts/gepa/test_gepa_local.sh +67 -0
- examples/blog_posts/gepa/verify_banking77_setup.sh +123 -0
- examples/blog_posts/mipro/README.md +415 -0
- examples/blog_posts/mipro/configs/banking77_mipro_local.toml +91 -0
- examples/blog_posts/mipro/configs/banking77_mipro_test.toml +87 -0
- examples/blog_posts/mipro/configs/banking77_pipeline_mipro_gemini_flash_lite_local.toml +98 -0
- examples/blog_posts/mipro/configs/banking77_pipeline_mipro_gpt41mini_local.toml +96 -0
- examples/blog_posts/mipro/configs/banking77_pipeline_mipro_local.toml +94 -0
- examples/blog_posts/mipro/configs/banking77_pipeline_mipro_test.toml +170 -0
- examples/blog_posts/mipro/deploy_banking77_pipeline_task_app.sh +59 -0
- examples/blog_posts/mipro/deploy_banking77_task_app.sh +41 -0
- examples/blog_posts/mipro/multi_step.md +79 -0
- examples/blog_posts/mipro/run_mipro_banking77.sh +191 -0
- examples/blog_posts/mipro/run_mipro_banking77_pipeline.sh +171 -0
- examples/blog_posts/mipro/run_mipro_banking77_pipeline_gemini_flash_lite.sh +177 -0
- examples/blog_posts/mipro/run_mipro_banking77_pipeline_gpt41mini.sh +173 -0
- examples/blog_posts/mipro/verify_banking77_setup.sh +117 -0
- examples/blog_posts/pokemon_vl/README.md +98 -0
- examples/blog_posts/pokemon_vl/configs/eval_gpt5nano.toml +26 -0
- examples/blog_posts/pokemon_vl/configs/eval_qwen3_vl.toml +27 -0
- examples/blog_posts/pokemon_vl/configs/eval_rl_final.toml +24 -0
- examples/blog_posts/pokemon_vl/configs/filter_high_reward.toml +10 -0
- examples/blog_posts/pokemon_vl/configs/train_rl_from_sft.toml +43 -0
- examples/blog_posts/pokemon_vl/configs/train_sft_qwen4b_vl.toml +40 -0
- examples/blog_posts/pokemon_vl/extract_images.py +239 -0
- examples/blog_posts/pokemon_vl/pokemon_vl_baseline.py +326 -0
- examples/blog_posts/pokemon_vl/run_eval_extract_images.py +209 -0
- examples/blog_posts/pokemon_vl/run_qwen_eval_extract_images.py +212 -0
- examples/blog_posts/pokemon_vl/text_box_analysis.md +106 -0
- examples/blog_posts/warming_up_to_rl/ARCHITECTURE.md +195 -0
- examples/blog_posts/warming_up_to_rl/FINAL_TEST_RESULTS.md +127 -0
- examples/blog_posts/warming_up_to_rl/INFERENCE_SUCCESS.md +132 -0
- examples/blog_posts/warming_up_to_rl/README.md +158 -0
- examples/blog_posts/warming_up_to_rl/SMOKE_TESTING.md +164 -0
- examples/blog_posts/warming_up_to_rl/SMOKE_TEST_COMPLETE.md +253 -0
- examples/blog_posts/warming_up_to_rl/configs/eval_baseline_qwen32b_10x20.toml +25 -0
- examples/blog_posts/warming_up_to_rl/configs/eval_ft_qwen4b.toml +25 -0
- examples/blog_posts/warming_up_to_rl/configs/eval_ft_qwen4b_10x20.toml +26 -0
- examples/blog_posts/warming_up_to_rl/configs/eval_groq_qwen32b.toml +25 -0
- examples/blog_posts/warming_up_to_rl/configs/eval_openai_gpt_oss_120b.toml +29 -0
- examples/blog_posts/warming_up_to_rl/configs/filter_high_reward_dataset.toml +10 -0
- examples/blog_posts/warming_up_to_rl/configs/smoke_test.toml +75 -0
- examples/blog_posts/warming_up_to_rl/configs/train_rl_from_sft.toml +91 -0
- examples/blog_posts/warming_up_to_rl/configs/train_sft_qwen4b.toml +40 -0
- examples/blog_posts/warming_up_to_rl/warming_up_to_rl_baseline.py +187 -0
- examples/crafter_debug_render.py +186 -0
- examples/dev/qwen3_32b_qlora_4xh100.toml +45 -0
- examples/gepa/banking77_pipeline_gepa.toml +96 -0
- examples/gepa/multi_stage_gepa_example.toml +84 -0
- examples/gepa/run_gepa_banking77_pipeline.sh +157 -0
- examples/multi_step/SFT_README.md +147 -0
- examples/multi_step/configs/README_verilog_rl.md +77 -0
- examples/multi_step/configs/VERILOG_REWARDS.md +103 -0
- examples/multi_step/configs/VERILOG_RL_CHECKLIST.md +196 -0
- examples/multi_step/configs/crafter_eval_synth_qwen4b.toml +35 -0
- examples/multi_step/configs/crafter_eval_text_only_groq_qwen32b.toml +36 -0
- examples/multi_step/configs/crafter_rl_outcome.toml +75 -0
- examples/multi_step/configs/crafter_rl_stepwise_hosted_judge.toml +145 -0
- examples/multi_step/configs/crafter_rl_stepwise_shaped.toml +84 -0
- examples/multi_step/configs/crafter_rl_stepwise_simple.toml +79 -0
- examples/multi_step/configs/crafter_rl_stepwise_simple_NEW_FORMAT.toml +105 -0
- examples/multi_step/configs/crafter_sft_qwen30b_lora.toml +62 -0
- examples/multi_step/configs/crafter_synth_backend.md +40 -0
- examples/multi_step/configs/verilog_eval_groq_qwen32b.toml +31 -0
- examples/multi_step/configs/verilog_eval_synth_qwen8b.toml +33 -0
- examples/multi_step/configs/verilog_rl_lora.toml +147 -0
- examples/multi_step/convert_traces_to_sft.py +84 -0
- examples/multi_step/crafter_rl_lora.md +70 -0
- examples/multi_step/judges/crafter_backend_judge.py +220 -0
- examples/multi_step/judges/verilog_backend_judge.py +234 -0
- examples/multi_step/readme.md +48 -0
- examples/multi_step/run_sft_qwen30b.sh +45 -0
- examples/multi_step/sse_metrics_streaming_notes.md +357 -0
- examples/multi_step/task_app_config_notes.md +494 -0
- examples/multi_step/verilog_rl_lora.md +218 -0
- examples/qwen_coder/README.md +102 -0
- examples/qwen_coder/_shared.py +113 -0
- examples/qwen_coder/configs/coder_lora_30b.toml +60 -0
- examples/qwen_coder/configs/coder_lora_4b.toml +61 -0
- examples/qwen_coder/configs/coder_lora_small.toml +57 -0
- examples/qwen_coder/generate_dataset.py +98 -0
- examples/qwen_coder/infer_ft_smoke.py +65 -0
- examples/qwen_coder/infer_prod_proxy.py +73 -0
- examples/qwen_coder/infer_via_synth.py +87 -0
- examples/qwen_coder/scripts/infer_coder.sh +19 -0
- examples/qwen_coder/scripts/train_coder_30b.sh +22 -0
- examples/qwen_coder/sft_full_17b.py +103 -0
- examples/qwen_coder/sft_lora_30b.py +110 -0
- examples/qwen_coder/subset_jsonl.py +39 -0
- examples/qwen_coder/todos.md +38 -0
- examples/qwen_coder/validate_jsonl.py +60 -0
- examples/qwen_vl/BUGS_AND_FIXES.md +232 -0
- examples/qwen_vl/IMAGE_VALIDATION_COMPLETE.md +271 -0
- examples/qwen_vl/IMAGE_VALIDATION_SUMMARY.md +260 -0
- examples/qwen_vl/INFERENCE_SFT_TESTS.md +412 -0
- examples/qwen_vl/NEXT_STEPS_2B.md +325 -0
- examples/qwen_vl/QUICKSTART.md +327 -0
- examples/qwen_vl/QUICKSTART_RL_VISION.md +110 -0
- examples/qwen_vl/README.md +152 -0
- examples/qwen_vl/RL_VISION_COMPLETE.md +475 -0
- examples/qwen_vl/RL_VISION_TESTING.md +333 -0
- examples/qwen_vl/SDK_VISION_INTEGRATION.md +328 -0
- examples/qwen_vl/SETUP_COMPLETE.md +274 -0
- examples/qwen_vl/VISION_TESTS_COMPLETE.md +489 -0
- examples/qwen_vl/VLM_PIPELINE_COMPLETE.md +242 -0
- examples/qwen_vl/__init__.py +2 -0
- examples/qwen_vl/collect_data_via_cli.md +415 -0
- examples/qwen_vl/collect_vision_traces.py +368 -0
- examples/qwen_vl/configs/crafter_rl_vision_qwen3vl4b.toml +110 -0
- examples/qwen_vl/configs/crafter_vlm_sft_example.toml +59 -0
- examples/qwen_vl/configs/eval_gpt4o_mini_vision.toml +26 -0
- examples/qwen_vl/configs/eval_gpt4o_vision_proper.toml +29 -0
- examples/qwen_vl/configs/eval_gpt5nano_vision.toml +26 -0
- examples/qwen_vl/configs/eval_qwen3vl_vision.toml +26 -0
- examples/qwen_vl/configs/filter_qwen3vl_sft.toml +49 -0
- examples/qwen_vl/configs/filter_vision_sft.toml +52 -0
- examples/qwen_vl/configs/filter_vision_test.toml +8 -0
- examples/qwen_vl/configs/sft_qwen3_vl_2b_test.toml +54 -0
- examples/qwen_vl/crafter_gpt5nano_agent.py +308 -0
- examples/qwen_vl/crafter_qwen_vl_agent.py +300 -0
- examples/qwen_vl/run_vision_comparison.sh +61 -0
- examples/qwen_vl/run_vision_sft_pipeline.sh +175 -0
- examples/qwen_vl/test_image_validation.py +201 -0
- examples/qwen_vl/test_sft_vision_data.py +110 -0
- examples/rl/README.md +169 -0
- examples/rl/configs/eval_base_qwen.toml +17 -0
- examples/rl/configs/eval_rl_qwen.toml +13 -0
- examples/rl/configs/rl_from_base_qwen.toml +62 -0
- examples/rl/configs/rl_from_base_qwen17.toml +80 -0
- examples/rl/configs/rl_from_ft_qwen.toml +37 -0
- examples/rl/download_dataset.py +80 -0
- examples/rl/run_eval.py +436 -0
- examples/rl/run_rl_and_save.py +111 -0
- examples/rl/task_app/README.md +21 -0
- {synth_ai/task/apps → examples/rl/task_app}/math_single_step.py +188 -50
- examples/rl/task_app/math_task_app.py +111 -0
- examples/run_crafter_demo.sh +10 -0
- examples/sdk_prompt_learning_example.py +55 -0
- examples/sft/README.md +139 -0
- examples/sft/configs/crafter_fft_qwen0p6b.toml +49 -0
- examples/sft/configs/crafter_lora_qwen0p6b.toml +49 -0
- examples/sft/evaluate.py +117 -0
- examples/sft/export_dataset.py +120 -0
- examples/sft/generate_traces.py +164 -0
- examples/swe/__init__.py +12 -0
- examples/swe/task_app/README.md +135 -0
- examples/swe/task_app/__init__.py +2 -0
- examples/swe/task_app/grpo_swe_mini.py +604 -0
- examples/swe/task_app/grpo_swe_mini_task_app.py +124 -0
- examples/swe/task_app/hosted/README.md +173 -0
- examples/swe/task_app/hosted/__init__.py +5 -0
- examples/swe/task_app/hosted/branching.py +143 -0
- examples/swe/task_app/hosted/environment_routes.py +1289 -0
- examples/swe/task_app/hosted/envs/__init__.py +1 -0
- examples/swe/task_app/hosted/envs/crafter/__init__.py +6 -0
- examples/swe/task_app/hosted/envs/crafter/app.py +1 -0
- examples/swe/task_app/hosted/envs/crafter/environment.py +522 -0
- examples/swe/task_app/hosted/envs/crafter/policy.py +478 -0
- examples/swe/task_app/hosted/envs/crafter/react_agent.py +108 -0
- examples/swe/task_app/hosted/envs/crafter/shared.py +305 -0
- examples/swe/task_app/hosted/envs/crafter/tools.py +47 -0
- examples/swe/task_app/hosted/envs/mini_swe/__init__.py +8 -0
- examples/swe/task_app/hosted/envs/mini_swe/environment.py +1191 -0
- examples/swe/task_app/hosted/envs/mini_swe/policy.py +355 -0
- examples/swe/task_app/hosted/envs/mini_swe/shared.py +83 -0
- examples/swe/task_app/hosted/envs/mini_swe/tools.py +96 -0
- examples/swe/task_app/hosted/hosted_app.py +204 -0
- examples/swe/task_app/hosted/inference/__init__.py +5 -0
- examples/swe/task_app/hosted/inference/openai_client.py +584 -0
- examples/swe/task_app/hosted/main.py +100 -0
- examples/swe/task_app/hosted/policy_routes.py +1094 -0
- examples/swe/task_app/hosted/registry.py +195 -0
- examples/swe/task_app/hosted/rollout.py +1905 -0
- examples/swe/task_app/hosted/storage/__init__.py +5 -0
- examples/swe/task_app/hosted/storage/volume.py +211 -0
- examples/swe/task_app/hosted/test_agents.py +161 -0
- examples/swe/task_app/hosted/test_service.py +136 -0
- examples/swe/task_app/hosted/utils.py +62 -0
- examples/swe/task_app/morph_backend.py +178 -0
- examples/task_apps/IMAGE_ONLY_EVAL_QUICKSTART.md +258 -0
- examples/task_apps/TESTING.md +275 -0
- examples/task_apps/banking77/__init__.py +6 -0
- examples/task_apps/banking77/banking77_task_app.py +912 -0
- examples/task_apps/banking77/deploy_wrapper.py +46 -0
- examples/task_apps/banking77_pipeline/__init__.py +6 -0
- examples/task_apps/banking77_pipeline/banking77_pipeline_task_app.py +489 -0
- examples/task_apps/banking77_pipeline/deploy_wrapper.py +50 -0
- examples/task_apps/crafter/CREATE_SFT_DATASET.md +286 -0
- examples/task_apps/crafter/EVAL_IMAGE_ONLY_RESULTS.md +152 -0
- examples/task_apps/crafter/FILTER_COMMAND_STATUS.md +187 -0
- examples/task_apps/crafter/FILTER_COMMAND_SUCCESS.md +281 -0
- examples/task_apps/crafter/QUERY_EXAMPLES.md +203 -0
- examples/task_apps/crafter/README_IMAGE_ONLY_EVAL.md +316 -0
- examples/task_apps/crafter/eval_image_only_gpt4o.toml +28 -0
- examples/task_apps/crafter/eval_text_only_groq_llama.toml +36 -0
- examples/task_apps/crafter/filter_sft_dataset.toml +16 -0
- examples/task_apps/crafter/task_app/README.md +42 -0
- examples/task_apps/crafter/task_app/__init__.py +5 -0
- examples/task_apps/crafter/task_app/grpo_crafter.py +1055 -0
- examples/task_apps/crafter/task_app/grpo_crafter_task_app.py +146 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/README.md +173 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/__init__.py +5 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/branching.py +143 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/environment_routes.py +1226 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/__init__.py +1 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/__init__.py +6 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/app.py +1 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/environment.py +532 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/policy.py +583 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/react_agent.py +122 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/shared.py +305 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/tools.py +47 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/hosted_app.py +253 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/inference/__init__.py +5 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/inference/openai_client.py +999 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/main.py +100 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/policy_routes.py +1252 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/registry.py +195 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/rollout.py +2233 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/storage/__init__.py +5 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/storage/volume.py +211 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/test_agents.py +161 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/test_service.py +136 -0
- examples/task_apps/crafter/task_app/synth_envs_hosted/utils.py +411 -0
- examples/task_apps/dev/pokemon_emerald/__init__.py +2 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/README.md +811 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/__init__.py +120 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/action.py +160 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/memory.py +155 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/perception.py +69 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/planning.py +96 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/simple.py +1502 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/system_prompt.py +4 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/grab_map.py +68 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/manual.py +216 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/__init__.py +35 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emerald_utils.py +631 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emulator.py +1544 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/enums.py +1428 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/memory_reader.py +4848 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/types.py +41 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/utils.py +298 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pyproject.toml +95 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/run.py +204 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/app.py +2152 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/client.py +429 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/frame_server.py +155 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/README.md +78 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/run_tests.py +122 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_direct.py +76 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_prompts.py +413 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_battle_state_formatting.py +204 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection.py +133 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection_comprehensive.py +229 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_direct_agent_emulator.py +300 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_fps_adjustment_pytest.py +205 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_direct.py +200 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_transition.py +284 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_map_ground_truth_comparison.py +468 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_memory_map.py +575 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_server_map_validation.py +311 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_torchic_state.py +259 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/anticheat.py +372 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/checkpoint.py +296 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/error_handler.py +275 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/get_local_ip.py +22 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/helpers.py +44 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/llm_logger.py +514 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_formatter.py +415 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher.py +1763 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher_singleton.py +33 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_trimmer.py +106 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_visualizer.py +334 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/ocr_dialogue.py +1020 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/recording.py +188 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/state_formatter.py +1481 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/vlm.py +862 -0
- examples/task_apps/dev/pokemon_emerald/modal_app.py +114 -0
- examples/task_apps/dev/pokemon_emerald/task_app/README.md +81 -0
- examples/task_apps/dev/pokemon_emerald/task_app/__init__.py +6 -0
- examples/task_apps/dev/pokemon_emerald/task_app/pokemon_emerald.py +685 -0
- examples/task_apps/enron/__init__.py +2 -0
- examples/task_apps/enron/eval_groq_qwen32.toml +16 -0
- examples/task_apps/enron/filter_sft.toml +5 -0
- examples/task_apps/enron/task_app/README.md +14 -0
- examples/task_apps/enron/task_app/__init__.py +1 -0
- examples/task_apps/enron/task_app/grpo_enron.py +906 -0
- examples/task_apps/enron/task_app/grpo_enron_task_app.py +146 -0
- examples/task_apps/enron/tests/__init__.py +4 -0
- examples/task_apps/enron/tests/conftest.py +115 -0
- examples/task_apps/enron/tests/integration/__init__.py +4 -0
- examples/task_apps/enron/tests/integration/test_enron_eval.py +179 -0
- examples/task_apps/enron/tests/integration/test_enron_rollout.py +135 -0
- examples/task_apps/enron/tests/unit/__init__.py +4 -0
- examples/task_apps/enron/tests/unit/test_enron_environment.py +126 -0
- examples/task_apps/gepa_benchmarks/__init__.py +7 -0
- examples/task_apps/gepa_benchmarks/common.py +260 -0
- examples/task_apps/gepa_benchmarks/hotpotqa_task_app.py +507 -0
- examples/task_apps/gepa_benchmarks/hover_task_app.py +436 -0
- examples/task_apps/gepa_benchmarks/ifbench_task_app.py +563 -0
- examples/task_apps/gepa_benchmarks/pupa_task_app.py +460 -0
- examples/task_apps/math/README.md +21 -0
- examples/task_apps/math/math_single_step.py +1000 -0
- examples/task_apps/math/math_task_app.py +115 -0
- examples/task_apps/pokemon_battle/__init__.py +2 -0
- examples/task_apps/pokemon_battle/modal_app.py +104 -0
- examples/task_apps/pokemon_battle/task_app/README.md +68 -0
- examples/task_apps/pokemon_battle/task_app/__init__.py +6 -0
- examples/task_apps/pokemon_battle/task_app/pokemon_showdown.py +932 -0
- examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_COMPLETE.md +283 -0
- examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_STATUS.md +155 -0
- examples/task_apps/pokemon_red/README.md +356 -0
- examples/task_apps/pokemon_red/README_IMAGE_ONLY_EVAL.md +428 -0
- examples/task_apps/pokemon_red/__init__.py +3 -0
- examples/task_apps/pokemon_red/eval_image_only_gpt4o.toml +30 -0
- examples/task_apps/pokemon_red/eval_pokemon_red_policy.py +224 -0
- examples/task_apps/pokemon_red/pallet_town_rl_config.toml +75 -0
- examples/task_apps/pokemon_red/task_app.py +1048 -0
- examples/task_apps/pokemon_red/test_pallet_town_rewards.py +193 -0
- examples/task_apps/sokoban/README.md +306 -0
- examples/task_apps/sokoban/__init__.py +3 -0
- examples/task_apps/sokoban/eval_groq_qwen32.toml +16 -0
- examples/task_apps/sokoban/eval_openai_gpt5.toml +16 -0
- examples/task_apps/sokoban/filter_sft.toml +5 -0
- examples/task_apps/sokoban/task_app.py +1058 -0
- examples/task_apps/sokoban/tests/__init__.py +4 -0
- examples/task_apps/sokoban/tests/conftest.py +113 -0
- examples/task_apps/sokoban/tests/integration/__init__.py +4 -0
- examples/task_apps/sokoban/tests/integration/test_sokoban_eval.py +57 -0
- examples/task_apps/sokoban/tests/integration/test_sokoban_rollout.py +198 -0
- examples/task_apps/sokoban/tests/unit/__init__.py +4 -0
- examples/task_apps/sokoban/tests/unit/test_sokoban_environment.py +114 -0
- examples/task_apps/verilog/__init__.py +1 -0
- examples/task_apps/verilog/eval_groq_qwen32b.toml +22 -0
- examples/task_apps/verilog/filter_sft.toml +5 -0
- examples/task_apps/verilog/task_app/README.md +12 -0
- examples/task_apps/verilog/task_app/__init__.py +1 -0
- examples/task_apps/verilog/task_app/grpo_verilog.py +1166 -0
- examples/task_apps/verilog/task_app/grpo_verilog_task_app.py +145 -0
- examples/task_apps/verilog/tests/__init__.py +4 -0
- examples/task_apps/verilog/tests/conftest.py +115 -0
- examples/task_apps/verilog/tests/integration/__init__.py +4 -0
- examples/task_apps/verilog/tests/integration/test_verilog_eval.py +181 -0
- examples/task_apps/verilog/tests/integration/test_verilog_rollout.py +55 -0
- examples/task_apps/verilog/tests/unit/__init__.py +4 -0
- examples/task_apps/verilog/tests/unit/test_verilog_scoring.py +118 -0
- examples/tunnel_gepa_banking77/README.md +106 -0
- examples/tunnel_gepa_banking77/banking77_gepa_tunnel.toml +95 -0
- examples/tunnel_gepa_banking77/keep_tunnel_running.py +60 -0
- examples/tunnel_gepa_banking77/run_gepa_with_tunnel.sh +226 -0
- examples/vlm/PROPOSAL.md +53 -0
- examples/vlm/README.md +68 -0
- examples/vlm/configs/crafter_vlm_gpt4o.toml +49 -0
- examples/vlm/crafter_image_only_agent.py +207 -0
- examples/vlm/crafter_openai_vlm_agent.py +275 -0
- examples/vlm/filter_image_rows.py +63 -0
- examples/vlm/run_crafter_vlm_benchmark.py +316 -0
- examples/warming_up_to_rl/_utils.py +92 -0
- examples/warming_up_to_rl/analyze_trace_db.py +422 -0
- examples/warming_up_to_rl/configs/crafter_fft.toml +53 -0
- examples/warming_up_to_rl/configs/crafter_fft_4b.toml +54 -0
- examples/warming_up_to_rl/configs/eval_fft_qwen4b.toml +22 -0
- examples/warming_up_to_rl/configs/eval_groq_qwen32b.toml +15 -0
- examples/warming_up_to_rl/configs/eval_modal_qwen4b.toml +24 -0
- examples/warming_up_to_rl/configs/eval_stepwise_complex.toml +35 -0
- examples/warming_up_to_rl/configs/eval_stepwise_consistent.toml +26 -0
- examples/warming_up_to_rl/configs/eval_stepwise_per_achievement.toml +36 -0
- examples/warming_up_to_rl/configs/eval_stepwise_simple.toml +32 -0
- examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +85 -0
- examples/warming_up_to_rl/configs/rl_from_ft.toml +58 -0
- examples/warming_up_to_rl/export_trace_sft.py +837 -0
- examples/warming_up_to_rl/groq_test.py +97 -0
- examples/warming_up_to_rl/manage_secrets.py +131 -0
- examples/warming_up_to_rl/old/event_rewards.md +234 -0
- examples/warming_up_to_rl/old/notes.md +73 -0
- examples/warming_up_to_rl/readme.md +110 -0
- examples/warming_up_to_rl/run_eval.py +736 -0
- examples/warming_up_to_rl/run_fft_and_save.py +380 -0
- examples/warming_up_to_rl/run_local_rollout.py +239 -0
- examples/warming_up_to_rl/run_local_rollout_modal.py +248 -0
- examples/warming_up_to_rl/run_local_rollout_parallel.py +405 -0
- examples/warming_up_to_rl/run_local_rollout_traced.py +477 -0
- examples/warming_up_to_rl/run_rl_and_save.py +124 -0
- examples/warming_up_to_rl/run_rollout_remote.py +156 -0
- examples/warming_up_to_rl/task_app/README.md +42 -0
- examples/warming_up_to_rl/task_app/grpo_crafter.py +876 -0
- examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +135 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/README.md +173 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/__init__.py +5 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/branching.py +143 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/environment_routes.py +1226 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/__init__.py +1 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/__init__.py +6 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/app.py +1 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +522 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +454 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +108 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +305 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/tools.py +47 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +253 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/__init__.py +5 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +729 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +100 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +1114 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +195 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +1891 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/__init__.py +5 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +211 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +161 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +137 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +129 -0
- examples/workflows/math_rl/configs/eval_base_qwen.toml +15 -0
- examples/workflows/math_rl/configs/eval_rl_qwen.toml +11 -0
- examples/workflows/math_rl/configs/rl_from_base_qwen.toml +62 -0
- examples/workflows/math_rl/configs/rl_from_base_qwen17.toml +80 -0
- examples/workflows/math_rl/configs/rl_from_ft_qwen.toml +35 -0
- examples/workflows/math_rl/download_dataset.py +80 -0
- examples/workflows/math_rl/run_eval.py +436 -0
- examples/workflows/math_rl/run_rl_and_save.py +111 -0
- synth_ai/__init__.py +47 -23
- synth_ai/_utils/__init__.py +47 -0
- synth_ai/_utils/base_url.py +10 -0
- synth_ai/_utils/http.py +10 -0
- synth_ai/_utils/prompts.py +10 -0
- synth_ai/_utils/task_app_state.py +12 -0
- synth_ai/_utils/user_config.py +10 -0
- synth_ai/api/models/supported.py +514 -0
- synth_ai/api/train/__init__.py +60 -2
- synth_ai/api/train/builders.py +347 -39
- synth_ai/api/train/cli.py +895 -160
- synth_ai/api/train/config_finder.py +103 -25
- synth_ai/api/train/configs/__init__.py +65 -0
- synth_ai/api/train/configs/prompt_learning.py +496 -0
- synth_ai/api/train/configs/rl.py +188 -0
- synth_ai/api/train/configs/sft.py +99 -0
- synth_ai/api/train/configs/shared.py +81 -0
- synth_ai/api/train/env_resolver.py +70 -20
- synth_ai/api/train/pollers.py +29 -4
- synth_ai/api/train/prompt_learning.py +425 -0
- synth_ai/api/train/sft.py +390 -0
- synth_ai/api/train/supported_algos.py +147 -0
- synth_ai/api/train/task_app.py +6 -4
- synth_ai/api/train/utils.py +64 -52
- synth_ai/api/train/validators.py +1117 -0
- synth_ai/api/tunnel.py +49 -0
- synth_ai/auth/credentials.py +94 -0
- synth_ai/baseline/__init__.py +25 -0
- synth_ai/baseline/config.py +209 -0
- synth_ai/baseline/discovery.py +214 -0
- synth_ai/baseline/execution.py +146 -0
- synth_ai/cfgs.py +227 -0
- synth_ai/cli/__init__.py +85 -63
- synth_ai/cli/_modal_wrapper.py +31 -0
- synth_ai/cli/_storage.py +20 -0
- synth_ai/cli/_typer_patch.py +47 -0
- synth_ai/cli/_validate_task_app.py +29 -0
- synth_ai/cli/balance.py +16 -4
- synth_ai/cli/calc.py +36 -21
- synth_ai/cli/claude.py +70 -0
- synth_ai/cli/codex.py +267 -0
- synth_ai/cli/commands/__init__.py +18 -0
- synth_ai/cli/commands/baseline/__init__.py +12 -0
- synth_ai/cli/commands/baseline/core.py +637 -0
- synth_ai/cli/commands/baseline/list.py +93 -0
- synth_ai/cli/commands/demo/__init__.py +6 -0
- synth_ai/cli/commands/demo/core.py +163 -0
- synth_ai/cli/commands/eval/__init__.py +19 -0
- synth_ai/cli/commands/eval/core.py +1112 -0
- synth_ai/cli/commands/eval/errors.py +81 -0
- synth_ai/cli/commands/eval/validation.py +133 -0
- synth_ai/cli/commands/filter/__init__.py +12 -0
- synth_ai/cli/commands/filter/core.py +424 -0
- synth_ai/cli/commands/filter/errors.py +55 -0
- synth_ai/cli/commands/filter/validation.py +77 -0
- synth_ai/cli/commands/help/__init__.py +185 -0
- synth_ai/cli/commands/help/core.py +72 -0
- synth_ai/cli/commands/smoke/__init__.py +7 -0
- synth_ai/cli/commands/smoke/core.py +1437 -0
- synth_ai/cli/commands/status/__init__.py +66 -0
- synth_ai/cli/commands/status/client.py +192 -0
- synth_ai/cli/commands/status/config.py +92 -0
- synth_ai/cli/commands/status/errors.py +20 -0
- synth_ai/cli/commands/status/formatters.py +164 -0
- synth_ai/cli/commands/status/subcommands/__init__.py +9 -0
- synth_ai/cli/commands/status/subcommands/files.py +79 -0
- synth_ai/cli/commands/status/subcommands/jobs.py +334 -0
- synth_ai/cli/commands/status/subcommands/models.py +79 -0
- synth_ai/cli/commands/status/subcommands/pricing.py +22 -0
- synth_ai/cli/commands/status/subcommands/runs.py +81 -0
- synth_ai/cli/commands/status/subcommands/session.py +183 -0
- synth_ai/cli/commands/status/subcommands/summary.py +47 -0
- synth_ai/cli/commands/status/subcommands/usage.py +203 -0
- synth_ai/cli/commands/status/utils.py +114 -0
- synth_ai/cli/commands/train/__init__.py +53 -0
- synth_ai/cli/commands/train/core.py +21 -0
- synth_ai/cli/commands/train/errors.py +117 -0
- synth_ai/cli/commands/train/judge_schemas.py +200 -0
- synth_ai/cli/commands/train/judge_validation.py +305 -0
- synth_ai/cli/commands/train/validation.py +386 -0
- synth_ai/cli/demo.py +32 -140
- synth_ai/cli/deploy.py +233 -0
- synth_ai/cli/eval/__init__.py +36 -0
- synth_ai/cli/eval/core.py +5 -0
- synth_ai/cli/eval/errors.py +31 -0
- synth_ai/cli/eval/validation.py +5 -0
- synth_ai/cli/filter/__init__.py +28 -0
- synth_ai/cli/filter/core.py +5 -0
- synth_ai/cli/filter/errors.py +23 -0
- synth_ai/cli/filter/validation.py +5 -0
- synth_ai/cli/legacy_root_backup.py +28 -22
- synth_ai/cli/lib/__init__.py +10 -0
- synth_ai/cli/lib/task_app_discovery.py +7 -0
- synth_ai/cli/lib/task_app_env.py +518 -0
- synth_ai/cli/mcp.py +34 -0
- synth_ai/cli/modal_serve/__init__.py +12 -0
- synth_ai/cli/modal_serve/core.py +14 -0
- synth_ai/cli/modal_serve/errors.py +8 -0
- synth_ai/cli/modal_serve/validation.py +11 -0
- synth_ai/cli/opencode.py +256 -0
- synth_ai/cli/recent.py +13 -7
- synth_ai/cli/rl_demo.py +156 -116
- synth_ai/cli/root.py +131 -132
- synth_ai/cli/serve/__init__.py +12 -0
- synth_ai/cli/serve/core.py +14 -0
- synth_ai/cli/serve/errors.py +8 -0
- synth_ai/cli/serve/validation.py +11 -0
- synth_ai/cli/setup.py +49 -0
- synth_ai/cli/status.py +7 -125
- synth_ai/cli/task_app_deploy.py +7 -0
- synth_ai/cli/task_app_list.py +25 -0
- synth_ai/cli/task_app_modal_serve.py +11 -0
- synth_ai/cli/task_app_serve.py +11 -0
- synth_ai/cli/task_apps.py +2284 -257
- synth_ai/cli/traces.py +9 -5
- synth_ai/cli/train/__init__.py +12 -0
- synth_ai/cli/train/core.py +21 -0
- synth_ai/cli/train/errors.py +8 -0
- synth_ai/cli/train/validation.py +24 -0
- synth_ai/cli/train.py +5 -0
- synth_ai/cli/turso.py +73 -0
- synth_ai/cli/watch.py +13 -18
- synth_ai/demos/__init__.py +10 -0
- synth_ai/demos/core/__init__.py +28 -1
- synth_ai/demos/core/cli.py +579 -291
- synth_ai/demos/crafter/__init__.py +1 -0
- synth_ai/demos/crafter/crafter_fft_4b.toml +55 -0
- synth_ai/demos/crafter/grpo_crafter_task_app.py +185 -0
- synth_ai/demos/crafter/rl_from_base_qwen4b.toml +74 -0
- synth_ai/demos/demo_registry.py +176 -0
- synth_ai/demos/demo_task_apps/__init__.py +3 -3
- synth_ai/demos/demo_task_apps/core.py +64 -28
- synth_ai/demos/demo_task_apps/crafter/__init__.py +1 -0
- synth_ai/demos/demo_task_apps/crafter/configs/crafter_fft_4b.toml +53 -0
- synth_ai/demos/demo_task_apps/crafter/configs/rl_from_base_qwen4b.toml +73 -0
- synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +184 -0
- synth_ai/demos/demo_task_apps/math/_common.py +1 -2
- synth_ai/demos/demo_task_apps/math/app.py +2 -1
- synth_ai/demos/demo_task_apps/math/deploy_modal.py +3 -6
- synth_ai/demos/demo_task_apps/math/modal_task_app.py +185 -83
- synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -2
- synth_ai/demos/math/__init__.py +1 -0
- synth_ai/demos/math/_common.py +16 -0
- synth_ai/demos/math/app.py +38 -0
- synth_ai/demos/math/config.toml +76 -0
- synth_ai/demos/math/deploy_modal.py +54 -0
- synth_ai/demos/math/modal_task_app.py +703 -0
- synth_ai/demos/math/task_app_entry.py +51 -0
- synth_ai/environments/environment/core.py +7 -1
- synth_ai/environments/examples/bandit/engine.py +12 -5
- synth_ai/environments/examples/bandit/environment.py +0 -1
- synth_ai/environments/examples/bandit/taskset.py +4 -4
- synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +7 -4
- synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +9 -5
- synth_ai/environments/examples/crafter_classic/environment.py +93 -2
- synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +4 -3
- synth_ai/environments/examples/enron/engine.py +7 -2
- synth_ai/environments/examples/enron/environment.py +68 -0
- synth_ai/environments/examples/red/engine.py +60 -12
- synth_ai/environments/examples/red/engine_helpers/memory_map.py +7 -0
- synth_ai/environments/examples/red/engine_helpers/reward_components.py +151 -179
- synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_progression.py +477 -0
- synth_ai/environments/examples/red/engine_helpers/state_extraction.py +32 -0
- synth_ai/environments/examples/red/environment.py +86 -0
- synth_ai/environments/examples/red/trace_hooks_v3.py +168 -0
- synth_ai/environments/examples/sokoban/taskset.py +116 -0
- synth_ai/environments/examples/verilog/engine.py +104 -12
- synth_ai/environments/examples/wordle/environment.py +0 -1
- synth_ai/environments/reproducibility/tree.py +5 -6
- synth_ai/environments/service/app.py +11 -12
- synth_ai/environments/service/core_routes.py +10 -9
- synth_ai/environments/stateful/engine.py +1 -1
- synth_ai/environments/tasks/core.py +1 -0
- synth_ai/environments/tasks/filters.py +5 -6
- synth_ai/environments/tasks/utils.py +4 -5
- synth_ai/evals/__init__.py +15 -0
- synth_ai/evals/base.py +14 -5
- synth_ai/evals/client.py +82 -0
- synth_ai/evals/types.py +42 -0
- synth_ai/http.py +8 -22
- synth_ai/http_client.py +45 -12
- synth_ai/inference/__init__.py +0 -2
- synth_ai/inference/client.py +21 -7
- synth_ai/jobs/client.py +129 -80
- synth_ai/judge_schemas.py +127 -0
- synth_ai/learning/__init__.py +51 -6
- synth_ai/learning/algorithms.py +14 -0
- synth_ai/learning/client.py +122 -30
- synth_ai/learning/config.py +2 -40
- synth_ai/learning/constants.py +0 -2
- synth_ai/learning/ft_client.py +4 -56
- synth_ai/learning/health.py +14 -8
- synth_ai/learning/jobs.py +43 -47
- synth_ai/learning/prompt_learning_client.py +276 -0
- synth_ai/learning/prompt_learning_types.py +185 -0
- synth_ai/{rl → learning/rl}/__init__.py +14 -5
- synth_ai/learning/rl/client.py +269 -0
- synth_ai/learning/rl/config.py +31 -0
- synth_ai/{rl → learning/rl}/contracts.py +5 -10
- synth_ai/{rl → learning/rl}/env_keys.py +45 -16
- synth_ai/learning/rl/secrets.py +13 -0
- synth_ai/learning/rl_client.py +2 -253
- synth_ai/learning/sft/__init__.py +29 -0
- synth_ai/learning/sft/client.py +68 -0
- synth_ai/learning/sft/config.py +270 -0
- synth_ai/learning/sft/data.py +698 -0
- synth_ai/learning/sse.py +25 -26
- synth_ai/learning/validators.py +29 -25
- synth_ai/mcp/__init__.py +5 -0
- synth_ai/mcp/__main__.py +8 -0
- synth_ai/mcp/main.py +254 -0
- synth_ai/mcp/setup.py +100 -0
- synth_ai/modal.py +257 -0
- synth_ai/pricing/__init__.py +3 -0
- synth_ai/pricing/model_pricing.py +64 -0
- synth_ai/session/__init__.py +75 -0
- synth_ai/session/client.py +383 -0
- synth_ai/session/constants.py +63 -0
- synth_ai/session/exceptions.py +105 -0
- synth_ai/session/manager.py +139 -0
- synth_ai/session/models.py +89 -0
- synth_ai/session/query.py +110 -0
- synth_ai/spec/__init__.py +46 -0
- synth_ai/spec/dataclasses.py +149 -0
- synth_ai/spec/loader.py +144 -0
- synth_ai/spec/serializer.py +199 -0
- synth_ai/spec/validation.py +250 -0
- synth_ai/streaming/__init__.py +29 -0
- synth_ai/streaming/config.py +94 -0
- synth_ai/streaming/handlers.py +589 -0
- synth_ai/streaming/streamer.py +320 -0
- synth_ai/streaming/types.py +95 -0
- synth_ai/task/__init__.py +50 -30
- synth_ai/task/apps/__init__.py +63 -19
- synth_ai/task/auth.py +35 -23
- synth_ai/task/client.py +15 -13
- synth_ai/task/config.py +261 -0
- synth_ai/task/contracts.py +165 -64
- synth_ai/task/datasets.py +9 -6
- synth_ai/task/errors.py +11 -10
- synth_ai/task/health.py +17 -11
- synth_ai/task/inference_api.py +101 -0
- synth_ai/task/json.py +58 -24
- synth_ai/task/proxy.py +59 -66
- synth_ai/task/rubrics/__init__.py +55 -0
- synth_ai/task/rubrics/loaders.py +156 -0
- synth_ai/task/rubrics/models.py +57 -0
- synth_ai/task/rubrics/scoring.py +116 -0
- synth_ai/task/rubrics/strict.py +149 -0
- synth_ai/task/rubrics.py +22 -15
- synth_ai/task/server.py +65 -31
- synth_ai/task/trace_correlation_helpers.py +328 -0
- synth_ai/task/tracing_utils.py +44 -28
- synth_ai/task/validators.py +449 -6
- synth_ai/task/vendors.py +5 -7
- synth_ai/tracing_v3/__init__.py +4 -0
- synth_ai/tracing_v3/abstractions.py +21 -4
- synth_ai/tracing_v3/config.py +167 -22
- synth_ai/tracing_v3/constants.py +21 -0
- synth_ai/tracing_v3/db_config.py +42 -29
- synth_ai/tracing_v3/decorators.py +80 -45
- synth_ai/tracing_v3/examples/basic_usage.py +15 -9
- synth_ai/tracing_v3/hooks.py +6 -4
- synth_ai/tracing_v3/llm_call_record_helpers.py +161 -61
- synth_ai/tracing_v3/migration_helper.py +1 -2
- synth_ai/tracing_v3/replica_sync.py +12 -7
- synth_ai/tracing_v3/serialization.py +130 -0
- synth_ai/tracing_v3/session_tracer.py +73 -16
- synth_ai/tracing_v3/storage/base.py +89 -1
- synth_ai/tracing_v3/storage/config.py +63 -16
- synth_ai/tracing_v3/storage/factory.py +11 -9
- synth_ai/tracing_v3/storage/utils.py +15 -11
- synth_ai/tracing_v3/trace_utils.py +317 -0
- synth_ai/tracing_v3/turso/__init__.py +8 -21
- synth_ai/tracing_v3/turso/daemon.py +123 -15
- synth_ai/tracing_v3/turso/models.py +5 -2
- synth_ai/tracing_v3/turso/native_manager.py +1293 -0
- synth_ai/tracing_v3/utils.py +5 -4
- synth_ai/tunnel.py +143 -0
- synth_ai/tunnel_deploy.py +278 -0
- synth_ai/types.py +8 -0
- synth_ai/urls.py +11 -0
- synth_ai/utils/__init__.py +166 -0
- synth_ai/utils/agents.py +74 -0
- synth_ai/utils/apps.py +152 -0
- synth_ai/utils/base_url.py +94 -0
- synth_ai/utils/bin.py +39 -0
- synth_ai/utils/claude.py +36 -0
- synth_ai/utils/cli.py +284 -0
- synth_ai/utils/config.py +81 -0
- synth_ai/utils/env.py +346 -0
- synth_ai/utils/errors.py +85 -0
- synth_ai/utils/http.py +172 -0
- synth_ai/utils/json.py +72 -0
- synth_ai/utils/log_filter.py +99 -0
- synth_ai/utils/logging.py +198 -0
- synth_ai/utils/modal.py +299 -0
- synth_ai/utils/paths.py +95 -0
- synth_ai/utils/process.py +233 -0
- synth_ai/utils/prompts.py +39 -0
- synth_ai/utils/sqld.py +122 -0
- synth_ai/utils/ssl.py +25 -0
- synth_ai/utils/task_app_discovery.py +882 -0
- synth_ai/utils/task_app_env.py +186 -0
- synth_ai/utils/task_app_state.py +318 -0
- synth_ai/utils/tunnel/__init__.py +12 -0
- synth_ai/utils/tunnel/config.py +55 -0
- synth_ai/utils/user_config.py +137 -0
- synth_ai/uvicorn.py +77 -0
- synth_ai-0.2.23.dev3.dist-info/METADATA +357 -0
- synth_ai-0.2.23.dev3.dist-info/RECORD +983 -0
- {synth_ai-0.2.9.dev0.dist-info → synth_ai-0.2.23.dev3.dist-info}/entry_points.txt +0 -1
- {synth_ai-0.2.9.dev0.dist-info → synth_ai-0.2.23.dev3.dist-info}/top_level.txt +1 -0
- synth_ai/cli/man.py +0 -106
- synth_ai/core/experiment.py +0 -15
- synth_ai/core/system.py +0 -15
- synth_ai/demo_registry.py +0 -258
- synth_ai/environments/examples/sokoban/units/astar_common.py +0 -95
- synth_ai/experimental/synth_oss.py +0 -446
- synth_ai/handshake.py +0 -107
- synth_ai/install_sqld.sh +0 -40
- synth_ai/learning/offline/dpo.py +0 -0
- synth_ai/learning/offline/providers.py +0 -7
- synth_ai/learning/offline/sft.py +0 -0
- synth_ai/learning/offline/shared.py +0 -0
- synth_ai/learning/online/grpo.py +0 -0
- synth_ai/learning/online/irft.py +0 -0
- synth_ai/learning/prompts/banking77_injection_eval.py +0 -168
- synth_ai/learning/prompts/gepa.py +0 -0
- synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +0 -213
- synth_ai/learning/prompts/mipro.py +0 -289
- synth_ai/learning/prompts/random_search.py +0 -246
- synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
- synth_ai/learning/prompts/run_random_search_banking77.py +0 -324
- synth_ai/lm/__init__.py +0 -51
- synth_ai/lm/caching/constants.py +0 -6
- synth_ai/lm/caching/dbs.py +0 -0
- synth_ai/lm/caching/ephemeral.py +0 -102
- synth_ai/lm/caching/handler.py +0 -137
- synth_ai/lm/caching/initialize.py +0 -11
- synth_ai/lm/caching/persistent.py +0 -114
- synth_ai/lm/config.py +0 -110
- synth_ai/lm/constants.py +0 -32
- synth_ai/lm/core/__init__.py +0 -8
- synth_ai/lm/core/all.py +0 -73
- synth_ai/lm/core/exceptions.py +0 -7
- synth_ai/lm/core/main.py +0 -319
- synth_ai/lm/core/main_v3.py +0 -594
- synth_ai/lm/core/synth_models.py +0 -48
- synth_ai/lm/core/vendor_clients.py +0 -188
- synth_ai/lm/cost/monitor.py +0 -1
- synth_ai/lm/cost/statefulness.py +0 -1
- synth_ai/lm/injection.py +0 -80
- synth_ai/lm/overrides.py +0 -206
- synth_ai/lm/provider_support/__init__.py +0 -8
- synth_ai/lm/provider_support/anthropic.py +0 -972
- synth_ai/lm/provider_support/openai.py +0 -1139
- synth_ai/lm/provider_support/suppress_logging.py +0 -31
- synth_ai/lm/structured_outputs/handler.py +0 -440
- synth_ai/lm/structured_outputs/inject.py +0 -297
- synth_ai/lm/structured_outputs/rehabilitate.py +0 -185
- synth_ai/lm/tools/__init__.py +0 -3
- synth_ai/lm/tools/base.py +0 -172
- synth_ai/lm/unified_interface.py +0 -202
- synth_ai/lm/vendors/base.py +0 -81
- synth_ai/lm/vendors/core/anthropic_api.py +0 -387
- synth_ai/lm/vendors/core/gemini_api.py +0 -292
- synth_ai/lm/vendors/core/mistral_api.py +0 -322
- synth_ai/lm/vendors/core/openai_api.py +0 -225
- synth_ai/lm/vendors/core/synth_dev_api.py +0 -0
- synth_ai/lm/vendors/local/ollama.py +0 -0
- synth_ai/lm/vendors/openai_standard.py +0 -780
- synth_ai/lm/vendors/openai_standard_responses.py +0 -256
- synth_ai/lm/vendors/retries.py +0 -22
- synth_ai/lm/vendors/supported/custom_endpoint.py +0 -417
- synth_ai/lm/vendors/supported/deepseek.py +0 -69
- synth_ai/lm/vendors/supported/grok.py +0 -75
- synth_ai/lm/vendors/supported/groq.py +0 -16
- synth_ai/lm/vendors/supported/ollama.py +0 -15
- synth_ai/lm/vendors/supported/openrouter.py +0 -74
- synth_ai/lm/vendors/supported/together.py +0 -11
- synth_ai/lm/vendors/synth_client.py +0 -808
- synth_ai/lm/warmup.py +0 -186
- synth_ai/rl/secrets.py +0 -19
- synth_ai/scripts/verify_rewards.py +0 -100
- synth_ai/task/apps/grpo_crafter.py +0 -438
- synth_ai/tracing/__init__.py +0 -30
- synth_ai/tracing_v1/__init__.py +0 -33
- synth_ai/tracing_v3/turso/manager.py +0 -774
- synth_ai/v0/tracing/abstractions.py +0 -224
- synth_ai/v0/tracing/base_client.py +0 -91
- synth_ai/v0/tracing/client_manager.py +0 -131
- synth_ai/v0/tracing/config.py +0 -142
- synth_ai/v0/tracing/context.py +0 -146
- synth_ai/v0/tracing/decorators.py +0 -682
- synth_ai/v0/tracing/events/__init__.py +0 -0
- synth_ai/v0/tracing/events/manage.py +0 -147
- synth_ai/v0/tracing/events/scope.py +0 -86
- synth_ai/v0/tracing/events/store.py +0 -228
- synth_ai/v0/tracing/immediate_client.py +0 -151
- synth_ai/v0/tracing/local.py +0 -18
- synth_ai/v0/tracing/log_client_base.py +0 -73
- synth_ai/v0/tracing/retry_queue.py +0 -186
- synth_ai/v0/tracing/trackers.py +0 -515
- synth_ai/v0/tracing/upload.py +0 -512
- synth_ai/v0/tracing/utils.py +0 -9
- synth_ai/v0/tracing_v1/__init__.py +0 -16
- synth_ai/v0/tracing_v1/abstractions.py +0 -224
- synth_ai/v0/tracing_v1/base_client.py +0 -91
- synth_ai/v0/tracing_v1/client_manager.py +0 -131
- synth_ai/v0/tracing_v1/config.py +0 -142
- synth_ai/v0/tracing_v1/context.py +0 -146
- synth_ai/v0/tracing_v1/decorators.py +0 -703
- synth_ai/v0/tracing_v1/events/__init__.py +0 -0
- synth_ai/v0/tracing_v1/events/manage.py +0 -147
- synth_ai/v0/tracing_v1/events/scope.py +0 -86
- synth_ai/v0/tracing_v1/events/store.py +0 -228
- synth_ai/v0/tracing_v1/immediate_client.py +0 -151
- synth_ai/v0/tracing_v1/local.py +0 -18
- synth_ai/v0/tracing_v1/log_client_base.py +0 -73
- synth_ai/v0/tracing_v1/retry_queue.py +0 -186
- synth_ai/v0/tracing_v1/trackers.py +0 -515
- synth_ai/v0/tracing_v1/upload.py +0 -527
- synth_ai/v0/tracing_v1/utils.py +0 -9
- synth_ai/zyk/__init__.py +0 -30
- synth_ai-0.2.9.dev0.dist-info/METADATA +0 -131
- synth_ai-0.2.9.dev0.dist-info/RECORD +0 -444
- {synth_ai/lm/caching → examples/task_apps}/__init__.py +0 -0
- {synth_ai/lm/cost → examples/task_apps/crafter}/__init__.py +0 -0
- {synth_ai/lm/structured_outputs → examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server}/__init__.py +0 -0
- {synth_ai/lm/vendors → examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests}/__init__.py +0 -0
- {synth_ai/lm/vendors/core → examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils}/__init__.py +0 -0
- {synth_ai/lm/vendors/local → examples/task_apps/math}/__init__.py +0 -0
- {synth_ai/lm/vendors/supported → examples/workflows}/__init__.py +0 -0
- {synth_ai/v0/tracing → examples/workflows/math_rl}/__init__.py +0 -0
- /synth_ai/{compound/cais.py → cli/__main__.py} +0 -0
- /synth_ai/{learning/filtering.py → py.typed} +0 -0
- {synth_ai-0.2.9.dev0.dist-info → synth_ai-0.2.23.dev3.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.9.dev0.dist-info → synth_ai-0.2.23.dev3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Image Validation Complete - Summary ✅
|
|
2
|
+
|
|
3
|
+
## Mission Accomplished
|
|
4
|
+
|
|
5
|
+
Added comprehensive validation for **invalid/bogus image content** to prevent errors before:
|
|
6
|
+
1. ❌ Wasted API calls to OpenAI/Groq/vLLM with invalid images
|
|
7
|
+
2. ❌ Wasted GPU hours training on corrupted datasets
|
|
8
|
+
3. ❌ Silent failures where models train on text-only when images expected
|
|
9
|
+
|
|
10
|
+
## What We Built
|
|
11
|
+
|
|
12
|
+
### 1. SDK Enhancement (`synth-ai`) ✅
|
|
13
|
+
|
|
14
|
+
**New Validation Logic:**
|
|
15
|
+
- `extract_image_urls()` - Filters out empty, null, whitespace-only, and non-string URLs
|
|
16
|
+
- `validate_vision_example()` - Strict validation that fails if ANY image entry is invalid
|
|
17
|
+
- Detects mismatches: "Has 2 image_url entries but only 1 valid URLs"
|
|
18
|
+
|
|
19
|
+
**Test Coverage:** 42/42 passing
|
|
20
|
+
- 6 existing SFT data tests
|
|
21
|
+
- 25 reasoning/thinking tests
|
|
22
|
+
- 11 NEW invalid image validation tests
|
|
23
|
+
|
|
24
|
+
### 2. Monorepo Integration ✅
|
|
25
|
+
|
|
26
|
+
**SFT Training Protection:**
|
|
27
|
+
- `backend/app/routes/simple_training/training/sft/data.py` (line 401-406)
|
|
28
|
+
- Already uses `sdk_validate_vision_example()`
|
|
29
|
+
- **Automatically protected** - no code changes needed!
|
|
30
|
+
|
|
31
|
+
**Inference Protection:**
|
|
32
|
+
- `backend/app/routes/simple_training/modal_service/gpu_functions.py` (line 3827-3915)
|
|
33
|
+
- Enhanced `_validate_inference_request()` with image validation
|
|
34
|
+
- **Now validates images before vLLM inference calls**
|
|
35
|
+
|
|
36
|
+
## Validation Examples
|
|
37
|
+
|
|
38
|
+
### ❌ **REJECTED** - Empty URL:
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"messages": [{
|
|
42
|
+
"role": "user",
|
|
43
|
+
"content": [
|
|
44
|
+
{"type": "text", "text": "What's this?"},
|
|
45
|
+
{"type": "image_url", "image_url": {"url": ""}} // ← CAUGHT!
|
|
46
|
+
]
|
|
47
|
+
}]
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
**Error:** `"Message 0: Has 1 image_url entries but only 0 valid URLs"`
|
|
51
|
+
|
|
52
|
+
### ❌ **REJECTED** - Missing URL field:
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"messages": [{
|
|
56
|
+
"role": "user",
|
|
57
|
+
"content": [
|
|
58
|
+
{"type": "image_url", "image_url": {}} // ← No url field!
|
|
59
|
+
]
|
|
60
|
+
}]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
**Error:** `"Message 0: Has 1 image_url entries but only 0 valid URLs"`
|
|
64
|
+
|
|
65
|
+
### ❌ **REJECTED** - Mixed valid/invalid (strict):
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"messages": [{
|
|
69
|
+
"role": "user",
|
|
70
|
+
"content": [
|
|
71
|
+
{"type": "image_url", "image_url": {"url": "https://valid.jpg"}}, // Valid
|
|
72
|
+
{"type": "image_url", "image_url": {"url": " "}} // ← Whitespace!
|
|
73
|
+
]
|
|
74
|
+
}]
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
**Error:** `"Message 0: Has 2 image_url entries but only 1 valid URLs"`
|
|
78
|
+
|
|
79
|
+
### ✅ **ACCEPTED** - Valid image:
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"messages": [
|
|
83
|
+
{
|
|
84
|
+
"role": "user",
|
|
85
|
+
"content": [
|
|
86
|
+
{"type": "text", "text": "Describe this"},
|
|
87
|
+
{"type": "image_url", "image_url": {"url": "https://example.com/img.jpg"}}
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
{"role": "assistant", "content": "A beautiful image"}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Test Coverage
|
|
96
|
+
|
|
97
|
+
### Invalid Image Tests (11 new):
|
|
98
|
+
```bash
|
|
99
|
+
✅ test_validate_vision_example_empty_url
|
|
100
|
+
✅ test_validate_vision_example_missing_url_field
|
|
101
|
+
✅ test_validate_vision_example_null_url
|
|
102
|
+
✅ test_validate_vision_example_malformed_image_dict
|
|
103
|
+
✅ test_validate_vision_example_non_string_url
|
|
104
|
+
✅ test_validate_vision_example_whitespace_only_url
|
|
105
|
+
✅ test_validate_vision_example_invalid_scheme
|
|
106
|
+
✅ test_validate_vision_example_multiple_invalid_urls
|
|
107
|
+
✅ test_validate_vision_example_mixed_valid_invalid
|
|
108
|
+
✅ test_extract_image_urls_filters_invalid
|
|
109
|
+
✅ test_validate_vision_example_invalid_base64_format
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Run Tests:
|
|
113
|
+
```bash
|
|
114
|
+
cd /Users/joshpurtell/Documents/GitHub/synth-ai
|
|
115
|
+
uv run pytest tests/unit/learning/test_sft_data.py -v
|
|
116
|
+
|
|
117
|
+
# Just invalid image tests:
|
|
118
|
+
uv run pytest tests/unit/learning/test_sft_data.py -k "invalid or bogus or empty_url or null_url or malformed or whitespace" -v
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Impact
|
|
122
|
+
|
|
123
|
+
### Before This Work ❌
|
|
124
|
+
- **Training:** Hours into GPU job before discovering dataset has empty image URLs
|
|
125
|
+
- **Inference:** Send request to OpenAI → get 400 error → debug → retry
|
|
126
|
+
- **Cost:** Waste $$ on API calls and GPU time for invalid data
|
|
127
|
+
- **Silent Failures:** Model trains on text-only, no one notices images missing
|
|
128
|
+
|
|
129
|
+
### After This Work ✅
|
|
130
|
+
- **Training:** Invalid examples caught during data prep, logged and skipped
|
|
131
|
+
- **Inference:** Request fails instantly with clear error before API call
|
|
132
|
+
- **Cost:** Zero waste - validation is instantaneous and local
|
|
133
|
+
- **Confidence:** All data validated, no silent failures possible
|
|
134
|
+
|
|
135
|
+
## Files Modified
|
|
136
|
+
|
|
137
|
+
### `synth-ai/` (SDK):
|
|
138
|
+
1. **`synth_ai/learning/sft/data.py`**
|
|
139
|
+
- Enhanced `extract_image_urls()` to filter invalid entries
|
|
140
|
+
- Enhanced `validate_vision_example()` with strict validation
|
|
141
|
+
- Added proper None checks for type safety
|
|
142
|
+
|
|
143
|
+
2. **`tests/unit/learning/test_sft_data.py`**
|
|
144
|
+
- Added 11 new invalid image validation tests
|
|
145
|
+
- All 42 tests passing ✅
|
|
146
|
+
|
|
147
|
+
3. **`examples/qwen_vl/IMAGE_VALIDATION_COMPLETE.md`**
|
|
148
|
+
- Detailed documentation with examples
|
|
149
|
+
|
|
150
|
+
### `monorepo/` (Backend):
|
|
151
|
+
1. **`backend/app/routes/simple_training/training/sft/data.py`**
|
|
152
|
+
- **No changes needed** - already uses SDK validation ✅
|
|
153
|
+
|
|
154
|
+
2. **`backend/app/routes/simple_training/modal_service/gpu_functions.py`**
|
|
155
|
+
- Enhanced `_validate_inference_request()` (line 3827-3915)
|
|
156
|
+
- Added image content validation for multimodal inference requests
|
|
157
|
+
- Self-contained (no SDK dependency for Modal deployment)
|
|
158
|
+
|
|
159
|
+
## Error Messages (Developer-Friendly)
|
|
160
|
+
|
|
161
|
+
All validation errors are **specific and actionable**:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# Empty URL
|
|
165
|
+
"Message 0: Image URL cannot be empty or whitespace-only"
|
|
166
|
+
|
|
167
|
+
# Missing URL field
|
|
168
|
+
"Message 0: Image entry missing URL field. Expected image_url.url or image field."
|
|
169
|
+
|
|
170
|
+
# Non-string URL
|
|
171
|
+
"Message 0: Image URL must be a string, got int"
|
|
172
|
+
|
|
173
|
+
# Mismatch count
|
|
174
|
+
"Message 0: Has 2 image_url entries but only 1 valid URLs. Some URLs are invalid, empty, or missing."
|
|
175
|
+
|
|
176
|
+
# No images when required
|
|
177
|
+
"No image content found in any message"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Validation Behavior
|
|
181
|
+
|
|
182
|
+
### `extract_image_urls()` - Filters out:
|
|
183
|
+
- ❌ Empty strings: `""`
|
|
184
|
+
- ❌ Whitespace-only: `" "`
|
|
185
|
+
- ❌ Non-strings: `None`, `123`, `[]`
|
|
186
|
+
- ❌ Missing `url` field
|
|
187
|
+
- ✅ Returns only valid URL strings
|
|
188
|
+
|
|
189
|
+
### `validate_vision_example()` - Strict:
|
|
190
|
+
- Counts `image_url` type entries vs valid URLs extracted
|
|
191
|
+
- **Fails if count mismatch** (some entries have invalid URLs)
|
|
192
|
+
- Warns about suspicious schemes (non-http/https/data:image)
|
|
193
|
+
- Validates each URL: must be non-empty string
|
|
194
|
+
|
|
195
|
+
### Inference Validation - Fail-Fast:
|
|
196
|
+
- Validates before vLLM API call
|
|
197
|
+
- Clear error messages
|
|
198
|
+
- Prevents wasted network/GPU time
|
|
199
|
+
|
|
200
|
+
## Future Enhancements (Optional)
|
|
201
|
+
|
|
202
|
+
1. **Base64 Decoding Validation:**
|
|
203
|
+
- Currently: Check URL string format only
|
|
204
|
+
- Future: Validate base64 can be decoded (add flag to avoid perf hit)
|
|
205
|
+
|
|
206
|
+
2. **Image Size Validation:**
|
|
207
|
+
- Currently: Any valid URL accepted
|
|
208
|
+
- Future: Check decoded image size limits (e.g., < 20MB)
|
|
209
|
+
|
|
210
|
+
3. **Format Validation:**
|
|
211
|
+
- Currently: URL scheme check only
|
|
212
|
+
- Future: Validate image format (PNG, JPEG, etc.) if base64
|
|
213
|
+
|
|
214
|
+
4. **Integration Tests:**
|
|
215
|
+
- Add E2E tests that submit invalid data to API
|
|
216
|
+
- Verify proper error responses
|
|
217
|
+
|
|
218
|
+
## Usage
|
|
219
|
+
|
|
220
|
+
### For SFT Training:
|
|
221
|
+
```python
|
|
222
|
+
from synth_ai.learning.sft.data import coerce_example, validate_vision_example
|
|
223
|
+
|
|
224
|
+
example = coerce_example(raw_data)
|
|
225
|
+
is_valid, error = validate_vision_example(example, require_images=True)
|
|
226
|
+
|
|
227
|
+
if not is_valid:
|
|
228
|
+
print(f"Skipping invalid example: {error}")
|
|
229
|
+
# Log and skip, don't train on this data
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### For Inference:
|
|
233
|
+
```python
|
|
234
|
+
# In monorepo backend, validation happens automatically:
|
|
235
|
+
# 1. API endpoint receives request
|
|
236
|
+
# 2. _validate_inference_request() called
|
|
237
|
+
# 3. If images invalid → ValueError raised → 400 error returned
|
|
238
|
+
# 4. If images valid → forwarded to vLLM
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Related Work
|
|
242
|
+
|
|
243
|
+
This builds on previous enhancements:
|
|
244
|
+
- **Reasoning Support:** Added `reasoning` and `raw_content` fields with validation
|
|
245
|
+
- **Vision Support:** Added multimodal message handling for Crafter VLM pipeline
|
|
246
|
+
- **SDK Integration:** Monorepo backend uses SDK for consistent data handling
|
|
247
|
+
|
|
248
|
+
## Status
|
|
249
|
+
|
|
250
|
+
✅ **Complete and Production-Ready**
|
|
251
|
+
|
|
252
|
+
- SDK enhanced with strict validation
|
|
253
|
+
- Comprehensive test coverage (42/42 passing)
|
|
254
|
+
- Monorepo SFT training automatically protected
|
|
255
|
+
- Monorepo inference validation added
|
|
256
|
+
- No lint errors
|
|
257
|
+
- Documentation complete
|
|
258
|
+
|
|
259
|
+
**Ready to catch bogus images before they cost you $$!** 💰
|
|
260
|
+
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# Vision Inference & SFT Integration Tests
|
|
2
|
+
|
|
3
|
+
Complete integration tests for vision inference and SFT training with multimodal data.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Two new test suites validate the full vision ML pipeline:
|
|
8
|
+
1. **Inference Tests** - Vision model inference with multimodal requests
|
|
9
|
+
2. **SFT Tests** - Supervised fine-tuning with vision data
|
|
10
|
+
|
|
11
|
+
## Test Files
|
|
12
|
+
|
|
13
|
+
### 1. Vision Inference Tests
|
|
14
|
+
**File:** `tests/integration/cli/test_cli_inference_vision.py`
|
|
15
|
+
|
|
16
|
+
**Tests:**
|
|
17
|
+
- `test_vision_inference_with_image` - Basic vision inference with image + text
|
|
18
|
+
- `test_vision_inference_validation` - Invalid image validation (empty URLs, etc.)
|
|
19
|
+
- `test_vision_inference_multiple_images` - Multiple images in one request
|
|
20
|
+
|
|
21
|
+
**What They Test:**
|
|
22
|
+
- ✅ Backend accepts multimodal messages
|
|
23
|
+
- ✅ Vision models process image + text input
|
|
24
|
+
- ✅ Image validation catches invalid data before inference
|
|
25
|
+
- ✅ Multiple image handling
|
|
26
|
+
- ✅ Response format validation
|
|
27
|
+
|
|
28
|
+
### 2. Vision SFT Tests
|
|
29
|
+
**File:** `tests/integration/cli/test_cli_train_sft_vision.py`
|
|
30
|
+
|
|
31
|
+
**Tests:**
|
|
32
|
+
- `test_cli_train_sft_vision_qwen2vl` - Full SFT training job submission
|
|
33
|
+
- `test_vision_sft_dataset_validation` - Dataset validation with mixed valid/invalid
|
|
34
|
+
- `test_cli_train_sft_vision_small_config` - Fast CI test with artifact config
|
|
35
|
+
|
|
36
|
+
**What They Test:**
|
|
37
|
+
- ✅ Vision SFT dataset creation with images
|
|
38
|
+
- ✅ Job submission for vision SFT training
|
|
39
|
+
- ✅ Backend accepts vision training config
|
|
40
|
+
- ✅ Dataset validation filters invalid examples
|
|
41
|
+
- ✅ LoRA training configuration for vision models
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
### Prerequisites
|
|
46
|
+
```bash
|
|
47
|
+
export SYNTH_API_KEY="your-api-key"
|
|
48
|
+
export BACKEND_BASE_URL="https://agent-learning.onrender.com/api"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Run Inference Tests
|
|
52
|
+
```bash
|
|
53
|
+
cd /Users/joshpurtell/Documents/GitHub/synth-ai
|
|
54
|
+
|
|
55
|
+
# All inference tests
|
|
56
|
+
uv run pytest tests/integration/cli/test_cli_inference_vision.py -v -s
|
|
57
|
+
|
|
58
|
+
# Single test
|
|
59
|
+
uv run pytest tests/integration/cli/test_cli_inference_vision.py::test_vision_inference_with_image -v
|
|
60
|
+
|
|
61
|
+
# With marks
|
|
62
|
+
uv run pytest -m "vision and slow" tests/integration/cli/test_cli_inference_vision.py
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Run SFT Tests
|
|
66
|
+
```bash
|
|
67
|
+
# All SFT tests
|
|
68
|
+
uv run pytest tests/integration/cli/test_cli_train_sft_vision.py -v -s
|
|
69
|
+
|
|
70
|
+
# Dataset validation only (fast)
|
|
71
|
+
uv run pytest tests/integration/cli/test_cli_train_sft_vision.py::test_vision_sft_dataset_validation -v
|
|
72
|
+
|
|
73
|
+
# Small config test (job submission)
|
|
74
|
+
uv run pytest tests/integration/cli/test_cli_train_sft_vision.py::test_cli_train_sft_vision_small_config -v
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Run All Vision Tests
|
|
78
|
+
```bash
|
|
79
|
+
# All vision tests (inference + SFT + RL)
|
|
80
|
+
uv run pytest -m vision -v -s
|
|
81
|
+
|
|
82
|
+
# Vision tests without slow ones
|
|
83
|
+
uv run pytest -m "vision and not slow" -v
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Test Details
|
|
87
|
+
|
|
88
|
+
### Inference Test 1: Basic Vision Inference
|
|
89
|
+
**Function:** `test_vision_inference_with_image`
|
|
90
|
+
|
|
91
|
+
**Creates:**
|
|
92
|
+
- Simple 64x64 red image (base64 encoded)
|
|
93
|
+
- Multimodal request with text + image
|
|
94
|
+
- POST to `/v1/chat/completions`
|
|
95
|
+
|
|
96
|
+
**Validates:**
|
|
97
|
+
- Response has `choices` array
|
|
98
|
+
- Choice has `message` with `content`
|
|
99
|
+
- Content is non-empty string
|
|
100
|
+
|
|
101
|
+
**Expected Output:**
|
|
102
|
+
```
|
|
103
|
+
✅ Vision inference successful
|
|
104
|
+
Model: Qwen/Qwen2-VL-2B-Instruct
|
|
105
|
+
Response: This image is red...
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Runtime:** ~10-20 seconds (depends on model loading)
|
|
109
|
+
|
|
110
|
+
### Inference Test 2: Validation
|
|
111
|
+
**Function:** `test_vision_inference_validation`
|
|
112
|
+
|
|
113
|
+
**Tests Invalid Requests:**
|
|
114
|
+
1. Empty image URL: `{"url": ""}`
|
|
115
|
+
2. Missing URL field: `{"image_url": {}}`
|
|
116
|
+
3. Whitespace URL: `{"url": " "}`
|
|
117
|
+
|
|
118
|
+
**Validates:**
|
|
119
|
+
- Backend returns 4xx error (validation failure)
|
|
120
|
+
- Error message indicates the problem
|
|
121
|
+
- No wasted inference on invalid data
|
|
122
|
+
|
|
123
|
+
**Expected Output:**
|
|
124
|
+
```
|
|
125
|
+
✅ Correctly rejected: Empty image URL
|
|
126
|
+
Error code: 400
|
|
127
|
+
Error message: Image URL cannot be empty...
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Inference Test 3: Multiple Images
|
|
131
|
+
**Function:** `test_vision_inference_multiple_images`
|
|
132
|
+
|
|
133
|
+
**Creates:**
|
|
134
|
+
- Red and blue test images
|
|
135
|
+
- Single message with 2 images
|
|
136
|
+
|
|
137
|
+
**Validates:**
|
|
138
|
+
- Backend handles multiple images
|
|
139
|
+
- Model processes both images
|
|
140
|
+
- Response mentions both colors (if model supports)
|
|
141
|
+
|
|
142
|
+
**Note:** May skip if model doesn't support multiple images per message.
|
|
143
|
+
|
|
144
|
+
### SFT Test 1: Full Training Job
|
|
145
|
+
**Function:** `test_cli_train_sft_vision_qwen2vl`
|
|
146
|
+
|
|
147
|
+
**Creates:**
|
|
148
|
+
- 3-example vision SFT dataset (JSONL)
|
|
149
|
+
- Each example has 1 image (base64 in data URL)
|
|
150
|
+
- Minimal training config (1 epoch, LoRA)
|
|
151
|
+
|
|
152
|
+
**Submits:**
|
|
153
|
+
- SFT training job via CLI
|
|
154
|
+
- Model: Qwen2-VL-2B-Instruct
|
|
155
|
+
- Config includes `supports_vision = true`
|
|
156
|
+
|
|
157
|
+
**Validates:**
|
|
158
|
+
- Job created successfully
|
|
159
|
+
- Job ID returned
|
|
160
|
+
- Config accepted by backend
|
|
161
|
+
|
|
162
|
+
**Expected Output:**
|
|
163
|
+
```
|
|
164
|
+
✅ Vision SFT job created: job-abc123
|
|
165
|
+
Model: Qwen2-VL-2B-Instruct
|
|
166
|
+
Dataset: /tmp/.../vision_sft_test.jsonl
|
|
167
|
+
Examples: 3 (with images)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Runtime:** ~30-60 seconds (job submission only, not training)
|
|
171
|
+
|
|
172
|
+
### SFT Test 2: Dataset Validation
|
|
173
|
+
**Function:** `test_vision_sft_dataset_validation`
|
|
174
|
+
|
|
175
|
+
**Creates:**
|
|
176
|
+
- 4-example dataset (2 valid, 2 invalid)
|
|
177
|
+
- Invalid examples have empty/missing URLs
|
|
178
|
+
|
|
179
|
+
**Validates:**
|
|
180
|
+
- SDK validation correctly identifies valid examples
|
|
181
|
+
- Invalid examples are flagged with specific errors
|
|
182
|
+
- No false positives or negatives
|
|
183
|
+
|
|
184
|
+
**Expected Output:**
|
|
185
|
+
```
|
|
186
|
+
✅ Example 0: Valid
|
|
187
|
+
❌ Example 1: Invalid - Has 1 image_url entries but only 0 valid URLs
|
|
188
|
+
❌ Example 2: Invalid - Has 1 image_url entries but only 0 valid URLs
|
|
189
|
+
✅ Example 3: Valid
|
|
190
|
+
|
|
191
|
+
✅ Dataset validation working correctly
|
|
192
|
+
Total examples: 4
|
|
193
|
+
Valid: 2
|
|
194
|
+
Invalid: 2
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Runtime:** ~1-2 seconds (pure validation, no network)
|
|
198
|
+
|
|
199
|
+
### SFT Test 3: Fast CI Test
|
|
200
|
+
**Function:** `test_cli_train_sft_vision_small_config`
|
|
201
|
+
|
|
202
|
+
**Uses:**
|
|
203
|
+
- Artifact config (`tests/artifacts/configs/sft.vision.small.toml`)
|
|
204
|
+
- Minimal settings for fast validation
|
|
205
|
+
|
|
206
|
+
**Validates:**
|
|
207
|
+
- Same as Test 1 but faster
|
|
208
|
+
- Config artifact is correct
|
|
209
|
+
|
|
210
|
+
**Runtime:** ~20-40 seconds
|
|
211
|
+
|
|
212
|
+
## Dataset Format
|
|
213
|
+
|
|
214
|
+
### Vision SFT Example
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"messages": [
|
|
218
|
+
{
|
|
219
|
+
"role": "user",
|
|
220
|
+
"content": [
|
|
221
|
+
{"type": "text", "text": "What color is this?"},
|
|
222
|
+
{
|
|
223
|
+
"type": "image_url",
|
|
224
|
+
"image_url": {
|
|
225
|
+
"url": "data:image/png;base64,iVBORw0KG..."
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"role": "assistant",
|
|
232
|
+
"content": "This image is red."
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
"metadata": {"example_id": 1}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Supported Image Formats
|
|
240
|
+
- **Data URLs:** `data:image/png;base64,<base64-data>`
|
|
241
|
+
- **HTTP URLs:** `https://example.com/image.jpg`
|
|
242
|
+
- **Local paths:** `/path/to/image.png` (converted to PIL Image)
|
|
243
|
+
|
|
244
|
+
### Validation Rules
|
|
245
|
+
✅ **Valid:**
|
|
246
|
+
- Non-empty URL string
|
|
247
|
+
- Valid scheme (http://, https://, data:image/)
|
|
248
|
+
- Properly formatted base64 (if data URL)
|
|
249
|
+
|
|
250
|
+
❌ **Invalid:**
|
|
251
|
+
- Empty string: `""`
|
|
252
|
+
- Whitespace only: `" "`
|
|
253
|
+
- Null value: `None` or `null`
|
|
254
|
+
- Missing URL field
|
|
255
|
+
- Non-string URL
|
|
256
|
+
|
|
257
|
+
## Integration with Other Tests
|
|
258
|
+
|
|
259
|
+
### Combined with RL Vision Tests
|
|
260
|
+
```bash
|
|
261
|
+
# All vision tests (inference + SFT + RL)
|
|
262
|
+
uv run pytest -m vision tests/integration/cli/ -v
|
|
263
|
+
|
|
264
|
+
# Specific pipeline
|
|
265
|
+
uv run pytest \
|
|
266
|
+
tests/integration/cli/test_cli_inference_vision.py \
|
|
267
|
+
tests/integration/cli/test_cli_train_sft_vision.py \
|
|
268
|
+
tests/integration/cli/test_cli_train_rl_vision.py \
|
|
269
|
+
-v -s
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Test Matrix
|
|
273
|
+
|
|
274
|
+
| Test Suite | Model | Data | Runtime | Purpose |
|
|
275
|
+
|------------|-------|------|---------|---------|
|
|
276
|
+
| Inference | Qwen2-VL-2B | Generated | ~20s | API validation |
|
|
277
|
+
| SFT | Qwen2-VL-2B | Generated | ~30s | Training job |
|
|
278
|
+
| RL | Qwen3-VL-4B | Task app | ~5-10min | Full pipeline |
|
|
279
|
+
|
|
280
|
+
## Troubleshooting
|
|
281
|
+
|
|
282
|
+
### Inference Test Fails
|
|
283
|
+
```bash
|
|
284
|
+
# Check backend connectivity
|
|
285
|
+
curl $BACKEND_BASE_URL/health
|
|
286
|
+
|
|
287
|
+
# Check API key
|
|
288
|
+
echo $SYNTH_API_KEY
|
|
289
|
+
|
|
290
|
+
# Verify model is available
|
|
291
|
+
curl -H "Authorization: Bearer $SYNTH_API_KEY" \
|
|
292
|
+
$BACKEND_BASE_URL/v1/models
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### SFT Test Fails
|
|
296
|
+
```bash
|
|
297
|
+
# Check dataset was created
|
|
298
|
+
cat /tmp/test_sft_vision/vision_sft_test.jsonl
|
|
299
|
+
|
|
300
|
+
# Validate dataset manually
|
|
301
|
+
python -c "
|
|
302
|
+
from synth_ai.learning.sft.data import load_jsonl, validate_vision_example
|
|
303
|
+
examples = load_jsonl('path/to/dataset.jsonl', min_messages=1)
|
|
304
|
+
for ex in examples:
|
|
305
|
+
is_valid, error = validate_vision_example(ex, require_images=True)
|
|
306
|
+
print(f'Valid: {is_valid}, Error: {error}')
|
|
307
|
+
"
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### PIL Not Available
|
|
311
|
+
```bash
|
|
312
|
+
# Install Pillow
|
|
313
|
+
uv pip install Pillow
|
|
314
|
+
|
|
315
|
+
# Or use conda
|
|
316
|
+
conda install pillow
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Image Too Large
|
|
320
|
+
```python
|
|
321
|
+
# Reduce image size in test
|
|
322
|
+
img = Image.new('RGB', (32, 32), color='red') # 32x32 instead of 64x64
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## CI Integration
|
|
326
|
+
|
|
327
|
+
### Pytest Marks
|
|
328
|
+
```python
|
|
329
|
+
@pytest.mark.slow # Takes >5 seconds
|
|
330
|
+
@pytest.mark.vision # Requires vision support
|
|
331
|
+
@pytest.mark.integration # Full integration test
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Run in CI
|
|
335
|
+
```yaml
|
|
336
|
+
# .github/workflows/test.yml
|
|
337
|
+
- name: Run vision integration tests
|
|
338
|
+
run: |
|
|
339
|
+
pytest -m "vision and integration" \
|
|
340
|
+
tests/integration/cli/test_cli_inference_vision.py \
|
|
341
|
+
tests/integration/cli/test_cli_train_sft_vision.py \
|
|
342
|
+
-v --tb=short
|
|
343
|
+
env:
|
|
344
|
+
SYNTH_API_KEY: ${{ secrets.SYNTH_API_KEY }}
|
|
345
|
+
BACKEND_BASE_URL: ${{ secrets.BACKEND_URL }}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Skip in Fast CI
|
|
349
|
+
```bash
|
|
350
|
+
# Skip slow tests for PR checks
|
|
351
|
+
pytest -m "not slow" tests/
|
|
352
|
+
|
|
353
|
+
# Include vision but skip slow
|
|
354
|
+
pytest -m "vision and not slow" tests/
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Performance Expectations
|
|
358
|
+
|
|
359
|
+
### Inference Tests
|
|
360
|
+
- **test_vision_inference_with_image:** 10-20s
|
|
361
|
+
- **test_vision_inference_validation:** 5-10s (3 requests)
|
|
362
|
+
- **test_vision_inference_multiple_images:** 15-25s
|
|
363
|
+
|
|
364
|
+
**Total:** ~30-55 seconds
|
|
365
|
+
|
|
366
|
+
### SFT Tests
|
|
367
|
+
- **test_vision_sft_dataset_validation:** 1-2s (local only)
|
|
368
|
+
- **test_cli_train_sft_vision_small_config:** 20-40s
|
|
369
|
+
- **test_cli_train_sft_vision_qwen2vl:** 30-60s
|
|
370
|
+
|
|
371
|
+
**Total:** ~50-100 seconds
|
|
372
|
+
|
|
373
|
+
### All Vision Tests (Inference + SFT + RL)
|
|
374
|
+
- **Total Runtime:** ~6-12 minutes
|
|
375
|
+
- **Network calls:** ~10-15
|
|
376
|
+
- **GPU time:** 0 (job submission only, not actual training)
|
|
377
|
+
|
|
378
|
+
## Related Documentation
|
|
379
|
+
|
|
380
|
+
- **RL Vision Tests:** `RL_VISION_TESTING.md`
|
|
381
|
+
- **Image Validation:** `IMAGE_VALIDATION_COMPLETE.md`
|
|
382
|
+
- **VLM Pipeline:** `VLM_PIPELINE_COMPLETE.md`
|
|
383
|
+
- **Quick Start:** `QUICKSTART_RL_VISION.md`
|
|
384
|
+
|
|
385
|
+
## Summary
|
|
386
|
+
|
|
387
|
+
✅ **Complete test coverage for vision ML pipeline:**
|
|
388
|
+
- Inference API with multimodal messages
|
|
389
|
+
- Image validation before inference
|
|
390
|
+
- SFT dataset creation and validation
|
|
391
|
+
- SFT training job submission
|
|
392
|
+
- Integration with existing RL vision tests
|
|
393
|
+
|
|
394
|
+
**Test Count:**
|
|
395
|
+
- Inference: 3 tests
|
|
396
|
+
- SFT: 3 tests
|
|
397
|
+
- RL: 3 tests (from previous work)
|
|
398
|
+
- **Total: 9 vision integration tests**
|
|
399
|
+
|
|
400
|
+
**Coverage:**
|
|
401
|
+
- ✅ End-to-end inference
|
|
402
|
+
- ✅ Request validation
|
|
403
|
+
- ✅ Dataset creation
|
|
404
|
+
- ✅ Dataset validation
|
|
405
|
+
- ✅ SFT job submission
|
|
406
|
+
- ✅ RL job submission
|
|
407
|
+
- ✅ Task app vision support
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
**Status:** Production-ready! Run `pytest -m vision -v` to validate the full vision ML pipeline from inference to RL training! 🎉
|
|
412
|
+
|