synth-ai 0.2.9.dev4__py3-none-any.whl → 0.2.9.dev6__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.
Potentially problematic release.
This version of synth-ai might be problematic. Click here for more details.
- examples/__init__.py +16 -0
- examples/crafter_debug_render.py +23 -17
- examples/qwen_coder/README.md +102 -0
- examples/qwen_coder/_shared.py +113 -0
- examples/qwen_coder/configs/coder_lora_30b.toml +61 -0
- examples/qwen_coder/configs/coder_lora_4b.toml +57 -0
- examples/qwen_coder/configs/coder_lora_small.toml +58 -0
- examples/qwen_coder/generate_dataset.py +98 -0
- examples/qwen_coder/infer_ft_smoke.py +64 -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 +18 -0
- examples/qwen_coder/scripts/train_coder_30b.sh +21 -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 +38 -0
- examples/qwen_coder/validate_jsonl.py +59 -0
- examples/rl/configs/eval_base_qwen.toml +1 -1
- examples/rl/configs/rl_from_base_qwen17.toml +1 -1
- examples/rl/download_dataset.py +26 -10
- examples/rl/run_eval.py +53 -52
- examples/rl/run_rl_and_save.py +29 -12
- examples/rl/task_app/math_single_step.py +180 -41
- examples/rl/task_app/math_task_app.py +14 -6
- examples/sft/README.md +139 -0
- examples/sft/configs/crafter_fft_qwen0p6b.toml +44 -0
- examples/sft/configs/crafter_lora_qwen0p6b.toml +45 -0
- examples/sft/evaluate.py +117 -0
- examples/sft/export_dataset.py +117 -0
- examples/sft/generate_traces.py +162 -0
- examples/swe/__init__.py +12 -0
- examples/swe/task_app/README.md +105 -0
- examples/swe/task_app/__init__.py +2 -0
- examples/swe/task_app/grpo_swe_mini.py +571 -0
- examples/swe/task_app/grpo_swe_mini_task_app.py +136 -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 +1164 -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 +618 -0
- examples/swe/task_app/hosted/main.py +100 -0
- examples/swe/task_app/hosted/policy_routes.py +1079 -0
- examples/swe/task_app/hosted/registry.py +195 -0
- examples/swe/task_app/hosted/rollout.py +1869 -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 +137 -0
- examples/swe/task_app/hosted/utils.py +62 -0
- examples/vlm/README.md +68 -0
- examples/vlm/configs/crafter_vlm_gpt4o.toml +44 -0
- examples/vlm/crafter_image_only_agent.py +207 -0
- examples/vlm/crafter_openai_vlm_agent.py +277 -0
- examples/vlm/filter_image_rows.py +63 -0
- examples/vlm/run_crafter_vlm_benchmark.py +316 -0
- examples/warming_up_to_rl/analyze_trace_db.py +12 -10
- examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +11 -1
- examples/warming_up_to_rl/export_trace_sft.py +218 -36
- examples/warming_up_to_rl/groq_test.py +15 -8
- examples/warming_up_to_rl/manage_secrets.py +29 -25
- examples/warming_up_to_rl/readme.md +9 -2
- examples/warming_up_to_rl/run_eval.py +137 -61
- examples/warming_up_to_rl/run_fft_and_save.py +131 -60
- examples/warming_up_to_rl/run_local_rollout.py +88 -39
- examples/warming_up_to_rl/run_local_rollout_modal.py +114 -28
- examples/warming_up_to_rl/run_local_rollout_parallel.py +81 -20
- examples/warming_up_to_rl/run_local_rollout_traced.py +126 -23
- examples/warming_up_to_rl/run_rl_and_save.py +35 -12
- examples/warming_up_to_rl/run_rollout_remote.py +44 -19
- examples/warming_up_to_rl/task_app/README.md +6 -2
- examples/warming_up_to_rl/task_app/grpo_crafter.py +319 -57
- examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +11 -30
- examples/warming_up_to_rl/task_app/synth_envs_hosted/__init__.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/branching.py +9 -11
- examples/warming_up_to_rl/task_app/synth_envs_hosted/environment_routes.py +137 -182
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/__init__.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/__init__.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/app.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +150 -57
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +105 -69
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +19 -7
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +45 -42
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/tools.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +47 -45
- examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/__init__.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +198 -92
- examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +0 -2
- examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +361 -263
- examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +21 -23
- examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +394 -274
- examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/__init__.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +56 -62
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +1 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +6 -15
- examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +4 -3
- synth/__init__.py +14 -0
- synth_ai/__init__.py +20 -4
- synth_ai/api/models/supported.py +376 -0
- synth_ai/api/train/builders.py +157 -26
- synth_ai/api/train/cli.py +213 -57
- synth_ai/api/train/config_finder.py +65 -5
- synth_ai/api/train/env_resolver.py +33 -15
- synth_ai/api/train/pollers.py +13 -4
- synth_ai/api/train/supported_algos.py +139 -0
- synth_ai/api/train/task_app.py +5 -3
- synth_ai/api/train/utils.py +33 -48
- synth_ai/cli/__init__.py +19 -4
- synth_ai/cli/_modal_wrapper.py +28 -0
- synth_ai/cli/_typer_patch.py +49 -0
- synth_ai/cli/balance.py +2 -3
- synth_ai/cli/calc.py +1 -1
- synth_ai/cli/demo.py +21 -6
- synth_ai/cli/recent.py +2 -2
- synth_ai/cli/rl_demo.py +77 -17
- synth_ai/cli/root.py +116 -39
- synth_ai/cli/status.py +2 -2
- synth_ai/cli/task_apps.py +1709 -243
- synth_ai/cli/traces.py +7 -4
- synth_ai/cli/turso.py +73 -0
- synth_ai/cli/watch.py +12 -18
- synth_ai/core/experiment.py +0 -2
- synth_ai/demo_registry.py +68 -31
- synth_ai/demos/core/cli.py +516 -194
- 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/configs/crafter_fft_4b.toml +2 -3
- synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +37 -30
- 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 +183 -82
- synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -2
- synth_ai/environments/examples/bandit/engine.py +12 -4
- synth_ai/environments/examples/bandit/taskset.py +4 -4
- synth_ai/environments/examples/crafter_classic/environment.py +76 -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/base.py +0 -2
- synth_ai/handshake.py +11 -9
- synth_ai/http.py +1 -1
- synth_ai/http_client.py +43 -11
- synth_ai/inference/__init__.py +0 -2
- synth_ai/inference/client.py +20 -6
- synth_ai/jobs/client.py +103 -78
- synth_ai/learning/__init__.py +41 -6
- synth_ai/learning/algorithms.py +14 -0
- synth_ai/learning/client.py +121 -29
- 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 +13 -7
- synth_ai/learning/jobs.py +43 -47
- synth_ai/{rl → learning/rl}/__init__.py +14 -5
- synth_ai/learning/rl/client.py +267 -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 +295 -0
- synth_ai/learning/sse.py +25 -26
- synth_ai/learning/validators.py +25 -24
- synth_ai/lm/__init__.py +21 -47
- synth_ai/task/__init__.py +26 -27
- synth_ai/task/apps/__init__.py +18 -19
- synth_ai/task/auth.py +35 -23
- synth_ai/task/client.py +15 -13
- synth_ai/task/contracts.py +37 -35
- synth_ai/task/datasets.py +9 -6
- synth_ai/task/errors.py +11 -10
- synth_ai/task/health.py +17 -11
- synth_ai/task/json.py +58 -24
- synth_ai/task/proxy.py +15 -14
- synth_ai/task/rubrics.py +22 -15
- synth_ai/task/server.py +43 -17
- synth_ai/task/tracing_utils.py +12 -7
- synth_ai/task/validators.py +0 -1
- synth_ai/task/vendors.py +5 -7
- synth_ai/tracing_v3/__init__.py +2 -0
- synth_ai/tracing_v3/abstractions.py +21 -4
- synth_ai/tracing_v3/db_config.py +26 -1
- synth_ai/tracing_v3/decorators.py +18 -15
- synth_ai/tracing_v3/examples/basic_usage.py +3 -2
- synth_ai/tracing_v3/hooks.py +6 -4
- synth_ai/tracing_v3/llm_call_record_helpers.py +6 -6
- synth_ai/tracing_v3/replica_sync.py +1 -0
- synth_ai/tracing_v3/session_tracer.py +63 -16
- synth_ai/tracing_v3/storage/base.py +89 -1
- synth_ai/tracing_v3/storage/config.py +21 -8
- synth_ai/tracing_v3/storage/factory.py +10 -8
- synth_ai/tracing_v3/storage/utils.py +4 -2
- synth_ai/tracing_v3/turso/daemon.py +7 -2
- synth_ai/tracing_v3/turso/models.py +5 -2
- synth_ai/tracing_v3/turso/native_manager.py +1173 -0
- synth_ai/tracing_v3/utils.py +4 -3
- synth_ai/v0/api/__init__.py +8 -0
- synth_ai/v0/api/models/__init__.py +8 -0
- synth_ai/v0/api/models/supported.py +8 -0
- synth_ai/v0/config/__init__.py +15 -0
- synth_ai/v0/config/base_url.py +12 -0
- synth_ai/v0/lm/__init__.py +51 -0
- synth_ai/{lm → v0/lm}/caching/ephemeral.py +3 -5
- synth_ai/{lm → v0/lm}/caching/handler.py +4 -4
- synth_ai/{lm → v0/lm}/caching/initialize.py +1 -1
- synth_ai/{lm → v0/lm}/caching/persistent.py +1 -1
- synth_ai/{lm → v0/lm}/config.py +6 -1
- synth_ai/{lm → v0/lm}/core/all.py +9 -9
- synth_ai/{lm → v0/lm}/core/exceptions.py +0 -2
- synth_ai/{lm → v0/lm}/core/main.py +19 -7
- synth_ai/{lm → v0/lm}/core/main_v3.py +10 -10
- synth_ai/{lm → v0/lm}/core/synth_models.py +2 -15
- synth_ai/{lm → v0/lm}/core/vendor_clients.py +6 -4
- synth_ai/{lm → v0/lm}/overrides.py +4 -4
- synth_ai/{lm → v0/lm}/provider_support/anthropic.py +4 -4
- synth_ai/{lm → v0/lm}/provider_support/openai.py +5 -5
- synth_ai/{lm → v0/lm}/structured_outputs/handler.py +5 -5
- synth_ai/{lm → v0/lm}/structured_outputs/rehabilitate.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/core/anthropic_api.py +16 -16
- synth_ai/{lm → v0/lm}/vendors/core/gemini_api.py +5 -5
- synth_ai/{lm → v0/lm}/vendors/core/mistral_api.py +5 -5
- synth_ai/{lm → v0/lm}/vendors/core/openai_api.py +12 -10
- synth_ai/{lm → v0/lm}/vendors/openai_standard.py +11 -9
- synth_ai/{lm → v0/lm}/vendors/openai_standard_responses.py +8 -5
- synth_ai/{lm → v0/lm}/vendors/supported/custom_endpoint.py +4 -6
- synth_ai/{lm → v0/lm}/vendors/supported/deepseek.py +2 -2
- synth_ai/{lm → v0/lm}/vendors/supported/grok.py +2 -2
- synth_ai/{lm → v0/lm}/vendors/supported/groq.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/supported/ollama.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/supported/openrouter.py +3 -3
- synth_ai/{lm → v0/lm}/vendors/supported/together.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/synth_client.py +38 -11
- synth_ai/v0/tracing/upload.py +32 -135
- synth_ai/v0/tracing_v3/__init__.py +10 -0
- synth_ai/v0/tracing_v3/abstractions.py +3 -0
- synth_ai/v0/tracing_v3/decorators.py +3 -0
- synth_ai/v0/tracing_v3/llm_call_record_helpers.py +3 -0
- synth_ai/v0/tracing_v3/session_tracer.py +3 -0
- synth_ai-0.2.9.dev6.dist-info/METADATA +191 -0
- {synth_ai-0.2.9.dev4.dist-info → synth_ai-0.2.9.dev6.dist-info}/RECORD +291 -264
- {synth_ai-0.2.9.dev4.dist-info → synth_ai-0.2.9.dev6.dist-info}/top_level.txt +1 -0
- examples/common_old/backend.py +0 -21
- examples/evals_old/README.md +0 -98
- examples/evals_old/__init__.py +0 -6
- examples/evals_old/compare_models.py +0 -1037
- examples/evals_old/example_log.md +0 -145
- examples/evals_old/run_demo.sh +0 -126
- examples/evals_old/trace_analysis.py +0 -270
- examples/finetuning_old/_backup_synth_qwen/config.toml +0 -29
- examples/finetuning_old/_backup_synth_qwen/example_log.md +0 -324
- examples/finetuning_old/_backup_synth_qwen/filter_traces.py +0 -60
- examples/finetuning_old/_backup_synth_qwen/filter_traces_achievements.py +0 -239
- examples/finetuning_old/_backup_synth_qwen/purge_v3_traces.py +0 -109
- examples/finetuning_old/_backup_synth_qwen/react_agent_lm.py +0 -1924
- examples/finetuning_old/_backup_synth_qwen/readme.md +0 -49
- examples/finetuning_old/_backup_synth_qwen/run_crafter_qwen4b.py +0 -114
- examples/finetuning_old/_backup_synth_qwen/run_demo.sh +0 -195
- examples/finetuning_old/_backup_synth_qwen/sft_kickoff.py +0 -118
- examples/finetuning_old/synth_qwen_v1/README.md +0 -68
- examples/finetuning_old/synth_qwen_v1/filter_traces.py +0 -60
- examples/finetuning_old/synth_qwen_v1/filter_traces_achievements.py +0 -239
- examples/finetuning_old/synth_qwen_v1/finetune.py +0 -46
- examples/finetuning_old/synth_qwen_v1/hello_ft_model.py +0 -71
- examples/finetuning_old/synth_qwen_v1/infer.py +0 -37
- examples/finetuning_old/synth_qwen_v1/poll.py +0 -44
- examples/finetuning_old/synth_qwen_v1/prepare_data.py +0 -35
- examples/finetuning_old/synth_qwen_v1/purge_v3_traces.py +0 -109
- examples/finetuning_old/synth_qwen_v1/react_agent_lm.py +0 -1932
- examples/finetuning_old/synth_qwen_v1/run_crafter_sft_job.py +0 -207
- examples/finetuning_old/synth_qwen_v1/run_ft_job.py +0 -232
- examples/finetuning_old/synth_qwen_v1/upload_data.py +0 -34
- examples/finetuning_old/synth_qwen_v1/util.py +0 -147
- examples/rl_old/task_app.py +0 -962
- examples/warming_up_to_rl/old/event_rewards.md +0 -234
- examples/warming_up_to_rl/old/notes.md +0 -73
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_stepwise_rewards.py +0 -58
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -738
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
- synth_ai/environments/examples/sokoban/units/astar_common.py +0 -95
- synth_ai/experimental/synth_oss.py +0 -446
- synth_ai/install_sqld.sh +0 -40
- synth_ai/learning/filtering.py +0 -0
- 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/rl/secrets.py +0 -19
- synth_ai/scripts/verify_rewards.py +0 -100
- synth_ai/tracing/__init__.py +0 -30
- synth_ai/tracing_v1/__init__.py +0 -33
- synth_ai/tracing_v3/turso/__init__.py +0 -25
- synth_ai/tracing_v3/turso/manager.py +0 -774
- synth_ai/zyk/__init__.py +0 -30
- synth_ai-0.2.9.dev4.dist-info/METADATA +0 -131
- /synth_ai/{lm → v0/lm}/caching/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/caching/constants.py +0 -0
- /synth_ai/{lm → v0/lm}/caching/dbs.py +0 -0
- /synth_ai/{lm → v0/lm}/constants.py +0 -0
- /synth_ai/{lm → v0/lm}/core/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/cost/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/cost/monitor.py +0 -0
- /synth_ai/{lm → v0/lm}/cost/statefulness.py +0 -0
- /synth_ai/{lm → v0/lm}/injection.py +0 -0
- /synth_ai/{lm → v0/lm}/provider_support/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/provider_support/suppress_logging.py +0 -0
- /synth_ai/{lm → v0/lm}/structured_outputs/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/structured_outputs/inject.py +0 -0
- /synth_ai/{lm → v0/lm}/tools/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/tools/base.py +0 -0
- /synth_ai/{lm → v0/lm}/unified_interface.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/base.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/core/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/core/synth_dev_api.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/local/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/local/ollama.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/retries.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/supported/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/warmup.py +0 -0
- {synth_ai-0.2.9.dev4.dist-info → synth_ai-0.2.9.dev6.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.9.dev4.dist-info → synth_ai-0.2.9.dev6.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.9.dev4.dist-info → synth_ai-0.2.9.dev6.dist-info}/licenses/LICENSE +0 -0
synth_ai/learning/validators.py
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
import json
|
|
5
|
-
from
|
|
6
|
-
from
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from synth_ai.learning.sft import SFTDataError, parse_jsonl_line
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def validate_training_jsonl(path: str | Path, *, sample_lines: int = 50) -> None:
|
|
10
11
|
p = Path(path)
|
|
11
12
|
if not p.exists():
|
|
12
13
|
raise FileNotFoundError(str(p))
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
max_samples = max(1, sample_lines)
|
|
16
|
+
non_empty_lines = 0
|
|
17
|
+
|
|
18
|
+
with p.open("r", encoding="utf-8") as fh:
|
|
19
|
+
for lineno, raw_line in enumerate(fh, start=1):
|
|
20
|
+
stripped = raw_line.strip()
|
|
21
|
+
if not stripped:
|
|
22
|
+
continue
|
|
23
|
+
non_empty_lines += 1
|
|
24
|
+
if non_empty_lines > max_samples:
|
|
25
|
+
break
|
|
26
|
+
try:
|
|
27
|
+
parse_jsonl_line(stripped, min_messages=2)
|
|
28
|
+
except json.JSONDecodeError as exc:
|
|
29
|
+
raise ValueError(f"invalid json on line {lineno}: {exc}") from exc
|
|
30
|
+
except SFTDataError as exc:
|
|
31
|
+
raise ValueError(f"line {lineno}: {exc}") from exc
|
|
32
|
+
|
|
33
|
+
if non_empty_lines == 0:
|
|
15
34
|
raise ValueError("empty JSONL")
|
|
16
|
-
for i, line in enumerate(lines[: max(1, sample_lines) ], start=1):
|
|
17
|
-
if not line.strip():
|
|
18
|
-
continue
|
|
19
|
-
try:
|
|
20
|
-
obj = json.loads(line)
|
|
21
|
-
except Exception as e:
|
|
22
|
-
raise ValueError(f"invalid json on line {i}: {e}") from e
|
|
23
|
-
msgs = obj.get("messages")
|
|
24
|
-
if not isinstance(msgs, list) or len(msgs) < 2:
|
|
25
|
-
raise ValueError(f"line {i}: missing messages[] with at least 2 turns")
|
|
26
|
-
roles = [m.get("role") for m in msgs if isinstance(m, dict)]
|
|
27
|
-
if not roles or not isinstance(roles[0], str):
|
|
28
|
-
raise ValueError(f"line {i}: missing first role")
|
|
29
|
-
for m in msgs:
|
|
30
|
-
if not isinstance(m, dict):
|
|
31
|
-
raise ValueError(f"line {i}: non-dict message")
|
|
32
|
-
if not isinstance(m.get("role"), str) or not isinstance(m.get("content"), str) or not m["content"].strip():
|
|
33
|
-
raise ValueError(f"line {i}: invalid role/content")
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
def validate_task_app_url(url: str, *, name: str = "TASK_APP_BASE_URL") -> None:
|
|
@@ -39,7 +40,7 @@ def validate_task_app_url(url: str, *, name: str = "TASK_APP_BASE_URL") -> None:
|
|
|
39
40
|
_vt(url, name=name)
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
def validate_trainer_cfg_rl(trainer:
|
|
43
|
+
def validate_trainer_cfg_rl(trainer: dict[str, Any]) -> None:
|
|
43
44
|
bs = int(trainer.get("batch_size", 1))
|
|
44
45
|
gs = int(trainer.get("group_size", 2))
|
|
45
46
|
if bs < 1:
|
synth_ai/lm/__init__.py
CHANGED
|
@@ -1,51 +1,25 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Synth AI Language Model Interface.
|
|
1
|
+
"""Deprecated shim forwarding to synth_ai.v0.lm."""
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import importlib as _importlib
|
|
4
|
+
import pkgutil as _pkgutil
|
|
5
|
+
import sys as _sys
|
|
6
|
+
from pathlib import Path as _Path
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from .unified_interface import (
|
|
10
|
-
OpenAIProvider,
|
|
11
|
-
SynthProvider,
|
|
12
|
-
UnifiedLMClient,
|
|
13
|
-
UnifiedLMProvider,
|
|
14
|
-
create_provider,
|
|
15
|
-
)
|
|
16
|
-
from .vendors.synth_client import (
|
|
17
|
-
AsyncSynthClient,
|
|
18
|
-
SyncSynthClient,
|
|
19
|
-
create_async_client,
|
|
20
|
-
create_chat_completion_async,
|
|
21
|
-
create_chat_completion_sync,
|
|
22
|
-
create_sync_client,
|
|
23
|
-
)
|
|
24
|
-
from .warmup import get_warmup_status, warmup_synth_model
|
|
8
|
+
_TARGET_PREFIX = "synth_ai.v0.lm"
|
|
9
|
+
_ALIAS_PREFIX = __name__
|
|
25
10
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"SynthConfig",
|
|
29
|
-
"OpenAIConfig",
|
|
30
|
-
# Warmup utilities
|
|
31
|
-
"warmup_synth_model",
|
|
32
|
-
"get_warmup_status",
|
|
33
|
-
# Unified interface
|
|
34
|
-
"UnifiedLMProvider",
|
|
35
|
-
"OpenAIProvider",
|
|
36
|
-
"SynthProvider",
|
|
37
|
-
"UnifiedLMClient",
|
|
38
|
-
"create_provider",
|
|
39
|
-
# Synth client
|
|
40
|
-
"AsyncSynthClient",
|
|
41
|
-
"SyncSynthClient",
|
|
42
|
-
"create_async_client",
|
|
43
|
-
"create_sync_client",
|
|
44
|
-
"create_chat_completion_async",
|
|
45
|
-
"create_chat_completion_sync",
|
|
46
|
-
# Core LM class
|
|
47
|
-
"LM",
|
|
48
|
-
]
|
|
11
|
+
_alias_path = _Path(__file__).resolve().parents[1] / "v0" / "lm"
|
|
12
|
+
__path__ = [str(_alias_path)] # type: ignore[assignment]
|
|
49
13
|
|
|
50
|
-
|
|
51
|
-
|
|
14
|
+
_pkg = _importlib.import_module(_TARGET_PREFIX)
|
|
15
|
+
_sys.modules[_ALIAS_PREFIX] = _pkg
|
|
16
|
+
|
|
17
|
+
for _finder, _name, _ispkg in _pkgutil.walk_packages(_pkg.__path__, prefix=_TARGET_PREFIX + "."): # type: ignore[attr-defined]
|
|
18
|
+
try:
|
|
19
|
+
_module = _importlib.import_module(_name)
|
|
20
|
+
except Exception: # pragma: no cover - best effort
|
|
21
|
+
continue
|
|
22
|
+
_alias = _ALIAS_PREFIX + _name[len(_TARGET_PREFIX) :]
|
|
23
|
+
_sys.modules[_alias] = _module
|
|
24
|
+
|
|
25
|
+
del _finder, _name, _ispkg, _module, _alias, _TARGET_PREFIX, _ALIAS_PREFIX, _alias_path
|
synth_ai/task/__init__.py
CHANGED
|
@@ -1,59 +1,58 @@
|
|
|
1
|
-
from .
|
|
2
|
-
|
|
1
|
+
from .auth import (
|
|
2
|
+
is_api_key_header_authorized,
|
|
3
|
+
normalize_environment_api_key,
|
|
4
|
+
require_api_key_dependency,
|
|
5
|
+
)
|
|
6
|
+
from .client import TaskAppClient
|
|
3
7
|
from .contracts import (
|
|
4
|
-
TaskAppContract,
|
|
5
|
-
TaskAppEndpoints,
|
|
6
8
|
RolloutEnvSpec,
|
|
9
|
+
RolloutMetrics,
|
|
7
10
|
RolloutPolicySpec,
|
|
8
11
|
RolloutRecordConfig,
|
|
9
|
-
RolloutSafetyConfig,
|
|
10
12
|
RolloutRequest,
|
|
11
13
|
RolloutResponse,
|
|
12
|
-
|
|
14
|
+
RolloutSafetyConfig,
|
|
13
15
|
RolloutStep,
|
|
14
|
-
|
|
16
|
+
RolloutTrajectory,
|
|
17
|
+
TaskAppContract,
|
|
18
|
+
TaskAppEndpoints,
|
|
15
19
|
TaskInfo,
|
|
16
20
|
)
|
|
21
|
+
from .datasets import TaskDatasetRegistry, TaskDatasetSpec
|
|
22
|
+
from .errors import error_payload, http_exception, json_error_response
|
|
23
|
+
from .health import task_app_health
|
|
17
24
|
from .json import to_jsonable
|
|
18
|
-
from .auth import (
|
|
19
|
-
normalize_environment_api_key,
|
|
20
|
-
is_api_key_header_authorized,
|
|
21
|
-
require_api_key_dependency,
|
|
22
|
-
)
|
|
23
|
-
from .vendors import (
|
|
24
|
-
normalize_vendor_keys,
|
|
25
|
-
get_openai_key_or_503,
|
|
26
|
-
get_groq_key_or_503,
|
|
27
|
-
)
|
|
28
25
|
from .proxy import (
|
|
29
26
|
INTERACT_TOOL_SCHEMA,
|
|
30
|
-
prepare_for_openai,
|
|
31
|
-
prepare_for_groq,
|
|
32
|
-
inject_system_hint,
|
|
33
27
|
extract_message_text,
|
|
28
|
+
inject_system_hint,
|
|
34
29
|
parse_tool_call_from_text,
|
|
30
|
+
prepare_for_groq,
|
|
31
|
+
prepare_for_openai,
|
|
35
32
|
synthesize_tool_call_if_missing,
|
|
36
33
|
)
|
|
37
|
-
from .datasets import TaskDatasetSpec, TaskDatasetRegistry
|
|
38
34
|
from .rubrics import (
|
|
39
35
|
Criterion,
|
|
40
36
|
Rubric,
|
|
41
|
-
load_rubric,
|
|
42
37
|
blend_rubrics,
|
|
38
|
+
load_rubric,
|
|
43
39
|
score_events_against_rubric,
|
|
44
40
|
score_outcome_against_rubric,
|
|
45
41
|
)
|
|
46
|
-
from .client import TaskAppClient
|
|
47
|
-
from .errors import error_payload, http_exception, json_error_response
|
|
48
|
-
|
|
49
|
-
|
|
50
42
|
from .server import (
|
|
51
|
-
TaskAppConfig,
|
|
52
43
|
ProxyConfig,
|
|
53
44
|
RubricBundle,
|
|
45
|
+
TaskAppConfig,
|
|
54
46
|
create_task_app,
|
|
55
47
|
run_task_app,
|
|
56
48
|
)
|
|
49
|
+
from .validators import validate_task_app_url
|
|
50
|
+
from .vendors import (
|
|
51
|
+
get_groq_key_or_503,
|
|
52
|
+
get_openai_key_or_503,
|
|
53
|
+
normalize_vendor_keys,
|
|
54
|
+
)
|
|
55
|
+
|
|
57
56
|
__all__ = [
|
|
58
57
|
"validate_task_app_url",
|
|
59
58
|
"task_app_health",
|
synth_ai/task/apps/__init__.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
"""Registry for Task Apps exposed via the shared FastAPI harness."""
|
|
4
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import importlib
|
|
6
|
-
import os
|
|
7
6
|
import sys
|
|
7
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
8
8
|
from dataclasses import dataclass, field
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import Callable, Dict, Iterable, List, Sequence
|
|
11
10
|
|
|
12
11
|
from ..server import TaskAppConfig
|
|
13
12
|
|
|
@@ -45,8 +44,8 @@ class TaskAppRegistry:
|
|
|
45
44
|
"""In-memory registry of known task apps."""
|
|
46
45
|
|
|
47
46
|
def __init__(self) -> None:
|
|
48
|
-
self._entries:
|
|
49
|
-
self._alias_to_id:
|
|
47
|
+
self._entries: dict[str, TaskAppEntry] = {}
|
|
48
|
+
self._alias_to_id: dict[str, str] = {}
|
|
50
49
|
|
|
51
50
|
def register(self, entry: TaskAppEntry) -> None:
|
|
52
51
|
if entry.app_id in self._entries:
|
|
@@ -63,12 +62,12 @@ class TaskAppRegistry:
|
|
|
63
62
|
raise KeyError(f"Unknown task app id: {app_id}")
|
|
64
63
|
return self._entries[resolved]
|
|
65
64
|
|
|
66
|
-
def list(self) ->
|
|
65
|
+
def list(self) -> list[TaskAppEntry]:
|
|
67
66
|
return sorted(self._entries.values(), key=lambda entry: entry.app_id)
|
|
68
67
|
|
|
69
68
|
def __iter__(self) -> Iterable[TaskAppEntry]:
|
|
70
69
|
return iter(self.list())
|
|
71
|
-
|
|
70
|
+
|
|
72
71
|
def clear(self) -> None:
|
|
73
72
|
"""Clear all registered task apps."""
|
|
74
73
|
self._entries.clear()
|
|
@@ -85,42 +84,42 @@ def register_task_app(*, entry: TaskAppEntry) -> None:
|
|
|
85
84
|
def discover_task_apps_from_cwd() -> None:
|
|
86
85
|
"""Discover and register task apps from the current working directory and subdirectories."""
|
|
87
86
|
cwd = Path.cwd()
|
|
88
|
-
|
|
87
|
+
|
|
89
88
|
# Look for task app files in common patterns
|
|
90
89
|
patterns = [
|
|
91
90
|
"**/task_app/*.py",
|
|
92
|
-
"**/task_apps/*.py",
|
|
91
|
+
"**/task_apps/*.py",
|
|
93
92
|
"**/*_task_app.py",
|
|
94
93
|
"**/grpo_crafter.py",
|
|
95
94
|
"**/math_single_step.py",
|
|
96
95
|
]
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
discovered_files = []
|
|
99
98
|
for pattern in patterns:
|
|
100
99
|
discovered_files.extend(cwd.glob(pattern))
|
|
101
|
-
|
|
100
|
+
|
|
102
101
|
# Add current directory to Python path temporarily
|
|
103
102
|
original_path = sys.path.copy()
|
|
104
103
|
try:
|
|
105
104
|
sys.path.insert(0, str(cwd))
|
|
106
|
-
|
|
105
|
+
|
|
107
106
|
for file_path in discovered_files:
|
|
108
|
-
if file_path.name.startswith(
|
|
107
|
+
if file_path.name.startswith("__"):
|
|
109
108
|
continue
|
|
110
|
-
|
|
109
|
+
|
|
111
110
|
# Convert file path to module name
|
|
112
111
|
relative_path = file_path.relative_to(cwd)
|
|
113
112
|
module_parts = list(relative_path.parts[:-1]) + [relative_path.stem]
|
|
114
|
-
module_name =
|
|
115
|
-
|
|
113
|
+
module_name = ".".join(module_parts)
|
|
114
|
+
|
|
116
115
|
try:
|
|
117
116
|
# Import the module to trigger registration
|
|
118
117
|
importlib.import_module(module_name)
|
|
119
|
-
except Exception
|
|
118
|
+
except Exception:
|
|
120
119
|
# Silently skip modules that can't be imported
|
|
121
120
|
# This allows for graceful handling of missing dependencies
|
|
122
121
|
continue
|
|
123
|
-
|
|
122
|
+
|
|
124
123
|
finally:
|
|
125
124
|
sys.path[:] = original_path
|
|
126
125
|
|
synth_ai/task/auth.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
"""Authentication helpers shared by Task Apps."""
|
|
4
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import os
|
|
6
|
-
from
|
|
6
|
+
from collections.abc import Iterable
|
|
7
|
+
from contextlib import suppress
|
|
8
|
+
from typing import Any
|
|
7
9
|
|
|
8
10
|
from .errors import http_exception
|
|
9
11
|
|
|
@@ -12,7 +14,9 @@ _DEV_API_KEY_ENVS = ("dev_environment_api_key", "DEV_ENVIRONMENT_API_KEY")
|
|
|
12
14
|
_API_KEY_HEADER = "x-api-key"
|
|
13
15
|
_API_KEYS_HEADER = "x-api-keys"
|
|
14
16
|
_AUTH_HEADER = "authorization"
|
|
15
|
-
_API_KEY_ALIASES_ENV =
|
|
17
|
+
_API_KEY_ALIASES_ENV = (
|
|
18
|
+
"ENVIRONMENT_API_KEY_ALIASES" # comma-separated list of additional valid keys
|
|
19
|
+
)
|
|
16
20
|
|
|
17
21
|
|
|
18
22
|
def _mask(value: str, *, prefix: int = 4) -> str:
|
|
@@ -22,7 +26,7 @@ def _mask(value: str, *, prefix: int = 4) -> str:
|
|
|
22
26
|
return f"{visible}{'…' if len(value) > prefix else ''}"
|
|
23
27
|
|
|
24
28
|
|
|
25
|
-
def normalize_environment_api_key() ->
|
|
29
|
+
def normalize_environment_api_key() -> str | None:
|
|
26
30
|
"""Ensure `ENVIRONMENT_API_KEY` is populated from dev fallbacks.
|
|
27
31
|
|
|
28
32
|
Returns the resolved key (if any) so callers can branch on configuration.
|
|
@@ -43,7 +47,7 @@ def normalize_environment_api_key() -> Optional[str]:
|
|
|
43
47
|
return None
|
|
44
48
|
|
|
45
49
|
|
|
46
|
-
def allowed_environment_api_keys() ->
|
|
50
|
+
def allowed_environment_api_keys() -> set[str]:
|
|
47
51
|
"""Return the set of valid environment API keys for this Task App.
|
|
48
52
|
|
|
49
53
|
Includes:
|
|
@@ -120,7 +124,9 @@ def require_api_key_dependency(request: Any) -> None:
|
|
|
120
124
|
|
|
121
125
|
allowed = allowed_environment_api_keys()
|
|
122
126
|
if not allowed:
|
|
123
|
-
raise http_exception(
|
|
127
|
+
raise http_exception(
|
|
128
|
+
503, "missing_environment_api_key", "ENVIRONMENT_API_KEY is not configured"
|
|
129
|
+
)
|
|
124
130
|
# Build candidate list for verbose diagnostics
|
|
125
131
|
single = list(_header_values(request, _API_KEY_HEADER))
|
|
126
132
|
multi = list(_header_values(request, _API_KEYS_HEADER))
|
|
@@ -131,23 +137,29 @@ def require_api_key_dependency(request: Any) -> None:
|
|
|
131
137
|
bearer.append(a.split(" ", 1)[1].strip())
|
|
132
138
|
candidates = _split_csv(single + multi + bearer)
|
|
133
139
|
if not any(candidate in allowed for candidate in candidates):
|
|
134
|
-
|
|
135
|
-
print(
|
|
136
|
-
|
|
140
|
+
with suppress(Exception):
|
|
141
|
+
print(
|
|
142
|
+
{
|
|
143
|
+
"task_auth_failed": True,
|
|
144
|
+
"allowed_first15": [k[:15] for k in allowed],
|
|
145
|
+
"allowed_count": len(allowed),
|
|
146
|
+
"got_first15": [c[:15] for c in candidates],
|
|
147
|
+
"got_lens": [len(c) for c in candidates],
|
|
148
|
+
"have_x_api_key": bool(single),
|
|
149
|
+
"have_x_api_keys": bool(multi),
|
|
150
|
+
"have_authorization": bool(auths),
|
|
151
|
+
},
|
|
152
|
+
flush=True,
|
|
153
|
+
)
|
|
154
|
+
# Use 400 to make failures unmistakable during preflight
|
|
155
|
+
raise http_exception(
|
|
156
|
+
400,
|
|
157
|
+
"unauthorised",
|
|
158
|
+
"API key missing or invalid",
|
|
159
|
+
extra={
|
|
137
160
|
"allowed_first15": [k[:15] for k in allowed],
|
|
138
161
|
"allowed_count": len(allowed),
|
|
139
162
|
"got_first15": [c[:15] for c in candidates],
|
|
140
163
|
"got_lens": [len(c) for c in candidates],
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"have_authorization": bool(auths),
|
|
144
|
-
}, flush=True)
|
|
145
|
-
except Exception:
|
|
146
|
-
pass
|
|
147
|
-
# Use 400 to make failures unmistakable during preflight
|
|
148
|
-
raise http_exception(400, "unauthorised", "API key missing or invalid", extra={
|
|
149
|
-
"allowed_first15": [k[:15] for k in allowed],
|
|
150
|
-
"allowed_count": len(allowed),
|
|
151
|
-
"got_first15": [c[:15] for c in candidates],
|
|
152
|
-
"got_lens": [len(c) for c in candidates],
|
|
153
|
-
})
|
|
164
|
+
},
|
|
165
|
+
)
|
synth_ai/task/client.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
"""Async HTTP client for interacting with Task Apps."""
|
|
4
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import asyncio
|
|
6
|
-
from typing import Any, Dict, Iterable, List, Optional
|
|
7
6
|
import os
|
|
7
|
+
from typing import Any
|
|
8
8
|
|
|
9
9
|
import httpx
|
|
10
10
|
from pydantic import BaseModel
|
|
@@ -37,7 +37,7 @@ class TaskAppClient:
|
|
|
37
37
|
self._client: httpx.AsyncClient | None = None
|
|
38
38
|
self.env = _TaskAppEnvironmentClient(self)
|
|
39
39
|
|
|
40
|
-
async def __aenter__(self) ->
|
|
40
|
+
async def __aenter__(self) -> TaskAppClient:
|
|
41
41
|
await self._ensure_client()
|
|
42
42
|
return self
|
|
43
43
|
|
|
@@ -53,8 +53,8 @@ class TaskAppClient:
|
|
|
53
53
|
)
|
|
54
54
|
return self._client
|
|
55
55
|
|
|
56
|
-
def _headers(self) ->
|
|
57
|
-
headers:
|
|
56
|
+
def _headers(self) -> dict[str, str]:
|
|
57
|
+
headers: dict[str, str] = {}
|
|
58
58
|
# Primary key
|
|
59
59
|
primary = (self.api_key or "").strip()
|
|
60
60
|
if primary:
|
|
@@ -85,7 +85,7 @@ class TaskAppClient:
|
|
|
85
85
|
method: str,
|
|
86
86
|
path: str,
|
|
87
87
|
*,
|
|
88
|
-
params:
|
|
88
|
+
params: dict[str, Any] | list[tuple[str, Any]] | None = None,
|
|
89
89
|
json_payload: Any = None,
|
|
90
90
|
) -> httpx.Response:
|
|
91
91
|
client = await self._ensure_client()
|
|
@@ -118,16 +118,16 @@ class TaskAppClient:
|
|
|
118
118
|
raise last_exc
|
|
119
119
|
raise RuntimeError("Unreachable code in TaskAppClient._request")
|
|
120
120
|
|
|
121
|
-
async def health(self) ->
|
|
121
|
+
async def health(self) -> dict[str, Any]:
|
|
122
122
|
response = await self._request("GET", "/health")
|
|
123
123
|
return response.json()
|
|
124
124
|
|
|
125
|
-
async def info(self) ->
|
|
125
|
+
async def info(self) -> dict[str, Any]:
|
|
126
126
|
response = await self._request("GET", "/info")
|
|
127
127
|
return response.json()
|
|
128
128
|
|
|
129
129
|
async def task_info(self, seeds: list[int] | None = None) -> TaskInfo | list[TaskInfo]:
|
|
130
|
-
params:
|
|
130
|
+
params: list[tuple[str, Any]] | None = None
|
|
131
131
|
if seeds:
|
|
132
132
|
params = [("seed", seed) for seed in seeds]
|
|
133
133
|
response = await self._request("GET", "/task_info", params=params)
|
|
@@ -146,19 +146,21 @@ class _TaskAppEnvironmentClient:
|
|
|
146
146
|
def __init__(self, client: TaskAppClient) -> None:
|
|
147
147
|
self._client = client
|
|
148
148
|
|
|
149
|
-
async def initialize(self, env_name: str, payload:
|
|
149
|
+
async def initialize(self, env_name: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
150
150
|
response = await self._client._request(
|
|
151
151
|
"POST", f"/env/{env_name}/initialize", json_payload=payload
|
|
152
152
|
)
|
|
153
153
|
return response.json()
|
|
154
154
|
|
|
155
|
-
async def step(self, env_name: str, payload:
|
|
155
|
+
async def step(self, env_name: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
156
156
|
response = await self._client._request(
|
|
157
157
|
"POST", f"/env/{env_name}/step", json_payload=payload
|
|
158
158
|
)
|
|
159
159
|
return response.json()
|
|
160
160
|
|
|
161
|
-
async def terminate(
|
|
161
|
+
async def terminate(
|
|
162
|
+
self, env_name: str, payload: dict[str, Any] | None = None
|
|
163
|
+
) -> dict[str, Any]:
|
|
162
164
|
response = await self._client._request(
|
|
163
165
|
"POST", f"/env/{env_name}/terminate", json_payload=payload or {}
|
|
164
166
|
)
|
synth_ai/task/contracts.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Any, Literal
|
|
5
|
+
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
|
|
7
8
|
|
|
@@ -40,23 +41,24 @@ class TaskAppContract:
|
|
|
40
41
|
"""
|
|
41
42
|
|
|
42
43
|
base_url: str
|
|
43
|
-
env_name:
|
|
44
|
+
env_name: str | None = None
|
|
44
45
|
requires_api_key_header: bool = True
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
# --- Unified rollout schema used by Task App services and SDK utilities ---
|
|
48
49
|
|
|
50
|
+
|
|
49
51
|
class RolloutEnvSpec(BaseModel):
|
|
50
|
-
env_id:
|
|
51
|
-
env_name:
|
|
52
|
-
config:
|
|
53
|
-
seed:
|
|
52
|
+
env_id: str | None = None
|
|
53
|
+
env_name: str | None = None
|
|
54
|
+
config: dict[str, Any] = Field(default_factory=dict)
|
|
55
|
+
seed: int | None = None
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
class RolloutPolicySpec(BaseModel):
|
|
57
|
-
policy_id:
|
|
58
|
-
policy_name:
|
|
59
|
-
config:
|
|
59
|
+
policy_id: str | None = None
|
|
60
|
+
policy_name: str | None = None
|
|
61
|
+
config: dict[str, Any] = Field(default_factory=dict)
|
|
60
62
|
|
|
61
63
|
|
|
62
64
|
class RolloutRecordConfig(BaseModel):
|
|
@@ -76,60 +78,60 @@ class RolloutRequest(BaseModel):
|
|
|
76
78
|
run_id: str
|
|
77
79
|
env: RolloutEnvSpec
|
|
78
80
|
policy: RolloutPolicySpec
|
|
79
|
-
ops:
|
|
81
|
+
ops: list[dict[str, Any]] | list[str]
|
|
80
82
|
record: RolloutRecordConfig = RolloutRecordConfig()
|
|
81
83
|
on_done: str = "reset"
|
|
82
84
|
safety: RolloutSafetyConfig = RolloutSafetyConfig()
|
|
83
|
-
training_session_id:
|
|
84
|
-
synth_base_url:
|
|
85
|
+
training_session_id: str | None = None
|
|
86
|
+
synth_base_url: str | None = None
|
|
85
87
|
|
|
86
88
|
|
|
87
89
|
class RolloutStep(BaseModel):
|
|
88
|
-
obs:
|
|
89
|
-
tool_calls:
|
|
90
|
-
reward:
|
|
90
|
+
obs: dict[str, Any]
|
|
91
|
+
tool_calls: list[dict[str, Any]]
|
|
92
|
+
reward: float | None = None
|
|
91
93
|
done: bool = False
|
|
92
|
-
truncated:
|
|
93
|
-
info:
|
|
94
|
+
truncated: bool | None = None
|
|
95
|
+
info: dict[str, Any] | None = None
|
|
94
96
|
|
|
95
97
|
|
|
96
98
|
class RolloutTrajectory(BaseModel):
|
|
97
99
|
env_id: str
|
|
98
100
|
policy_id: str
|
|
99
|
-
steps:
|
|
100
|
-
final:
|
|
101
|
+
steps: list[RolloutStep]
|
|
102
|
+
final: dict[str, Any] | None = None
|
|
101
103
|
length: int
|
|
102
104
|
|
|
103
105
|
|
|
104
106
|
class RolloutMetrics(BaseModel):
|
|
105
|
-
episode_returns:
|
|
107
|
+
episode_returns: list[float]
|
|
106
108
|
mean_return: float
|
|
107
109
|
num_steps: int
|
|
108
110
|
num_episodes: int = 0
|
|
109
|
-
outcome_score:
|
|
110
|
-
events_score:
|
|
111
|
-
details:
|
|
111
|
+
outcome_score: float | None = None
|
|
112
|
+
events_score: float | None = None
|
|
113
|
+
details: dict[str, Any] = Field(default_factory=dict)
|
|
112
114
|
|
|
113
115
|
|
|
114
116
|
class RolloutResponse(BaseModel):
|
|
115
117
|
run_id: str
|
|
116
|
-
trajectories:
|
|
117
|
-
branches:
|
|
118
|
+
trajectories: list[RolloutTrajectory]
|
|
119
|
+
branches: dict[str, list[str]] = Field(default_factory=dict)
|
|
118
120
|
metrics: RolloutMetrics
|
|
119
121
|
aborted: bool = False
|
|
120
122
|
ops_executed: int = 0
|
|
121
|
-
trace:
|
|
123
|
+
trace: dict[str, Any] | None = None
|
|
122
124
|
|
|
123
125
|
|
|
124
126
|
class TaskInfo(BaseModel):
|
|
125
127
|
"""Static metadata describing the capabilities of a Task App task."""
|
|
126
128
|
|
|
127
|
-
task:
|
|
128
|
-
environments:
|
|
129
|
-
action_space:
|
|
130
|
-
observation:
|
|
131
|
-
dataset:
|
|
132
|
-
rubric:
|
|
133
|
-
inference:
|
|
134
|
-
capabilities:
|
|
135
|
-
limits:
|
|
129
|
+
task: dict[str, Any]
|
|
130
|
+
environments: list[str]
|
|
131
|
+
action_space: dict[str, Any]
|
|
132
|
+
observation: dict[str, Any]
|
|
133
|
+
dataset: dict[str, Any]
|
|
134
|
+
rubric: dict[str, Any]
|
|
135
|
+
inference: dict[str, Any]
|
|
136
|
+
capabilities: dict[str, Any]
|
|
137
|
+
limits: dict[str, Any]
|
synth_ai/task/datasets.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
"""Dataset registry and helpers shared by Task Apps."""
|
|
4
2
|
|
|
5
|
-
from
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Hashable
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
from pydantic import BaseModel, Field, field_validator
|
|
8
9
|
|
|
@@ -34,10 +35,12 @@ class TaskDatasetRegistry:
|
|
|
34
35
|
"""Lightweight registry mapping dataset specs to loader callables."""
|
|
35
36
|
|
|
36
37
|
def __init__(self) -> None:
|
|
37
|
-
self._entries:
|
|
38
|
-
self._cache:
|
|
38
|
+
self._entries: dict[str, tuple[TaskDatasetSpec, RegistryLoader, bool]] = {}
|
|
39
|
+
self._cache: dict[Hashable, Any] = {}
|
|
39
40
|
|
|
40
|
-
def register(
|
|
41
|
+
def register(
|
|
42
|
+
self, spec: TaskDatasetSpec, loader: RegistryLoader, *, cache: bool = True
|
|
43
|
+
) -> None:
|
|
41
44
|
"""Register a dataset loader and its metadata."""
|
|
42
45
|
|
|
43
46
|
self._entries[spec.id] = (spec, loader, cache)
|