synth-ai 0.2.9.dev5__py3-none-any.whl → 0.2.10__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/dev/qwen3_32b_qlora_4xh100.toml +40 -0
- examples/multi_step/crafter_rl_lora.md +29 -0
- 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 +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/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/PROPOSAL.md +53 -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_ai/__init__.py +1 -0
- 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 +1699 -259
- 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.dev5.dist-info → synth_ai-0.2.10.dist-info}/METADATA +10 -7
- {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/RECORD +294 -258
- 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
- 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/{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.dev5.dist-info → synth_ai-0.2.10.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/licenses/LICENSE +0 -0
- {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/top_level.txt +0 -0
|
@@ -14,8 +14,10 @@ big “backend.production” code-base.
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
import gzip
|
|
17
|
+
import hashlib
|
|
17
18
|
import json
|
|
18
19
|
import logging
|
|
20
|
+
import os
|
|
19
21
|
import pickle
|
|
20
22
|
import sqlite3
|
|
21
23
|
from collections.abc import Iterable
|
|
@@ -32,11 +34,6 @@ log = logging.getLogger(__name__)
|
|
|
32
34
|
# --------------------------------------------------------------------------- #
|
|
33
35
|
# lightweight metadata record #
|
|
34
36
|
# --------------------------------------------------------------------------- #
|
|
35
|
-
import hashlib
|
|
36
|
-
import logging
|
|
37
|
-
import os
|
|
38
|
-
|
|
39
|
-
log = logging.getLogger(__name__)
|
|
40
37
|
|
|
41
38
|
# Default directory for storing snapshots relative to some base path
|
|
42
39
|
# This could be configured via environment variables or settings later.
|
|
@@ -256,7 +253,9 @@ class TrajectoryTreeStore:
|
|
|
256
253
|
def reconstruct_actions(self, snap_id: str) -> tuple[Any, ...]:
|
|
257
254
|
"""Return the sequence of *actions* from the root → `snap_id`."""
|
|
258
255
|
actions = []
|
|
259
|
-
for child, parent in zip(
|
|
256
|
+
for child, parent in zip(
|
|
257
|
+
self.path_to_root(snap_id)[:-1], self.path_to_root(snap_id)[1:], strict=False
|
|
258
|
+
):
|
|
260
259
|
actions.append(self.graph.edges[parent, child]["action"])
|
|
261
260
|
return tuple(reversed(actions))
|
|
262
261
|
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os # Added to ensure os is available before use
|
|
2
3
|
import sys
|
|
3
4
|
|
|
5
|
+
import synth_ai.environments.examples.crafter_classic.environment as cc
|
|
6
|
+
import synth_ai.environments.examples.crafter_custom.environment as ccustom
|
|
7
|
+
from fastapi import FastAPI
|
|
8
|
+
from synth_ai.environments.service.core_routes import api_router
|
|
9
|
+
from synth_ai.environments.service.external_registry import (
|
|
10
|
+
ExternalRegistryConfig,
|
|
11
|
+
load_external_environments,
|
|
12
|
+
)
|
|
13
|
+
from synth_ai.environments.service.registry import list_supported_env_types, register_environment
|
|
14
|
+
|
|
4
15
|
# Ensure repository root is on PYTHONPATH for dev installs
|
|
5
16
|
# Current file path: <repo>/synth_ai/environments/service/app.py
|
|
6
17
|
# We want sys.path to include <repo>, NOT <repo>/synth_ai to avoid shadowing stdlib 'http'
|
|
@@ -16,15 +27,6 @@ if _repo_root not in sys.path:
|
|
|
16
27
|
sys.path.insert(0, _repo_root)
|
|
17
28
|
|
|
18
29
|
print(f"SYS.PATH IN APP.PY: {sys.path}")
|
|
19
|
-
import logging
|
|
20
|
-
|
|
21
|
-
from fastapi import FastAPI
|
|
22
|
-
from synth_ai.environments.service.core_routes import api_router
|
|
23
|
-
from synth_ai.environments.service.external_registry import (
|
|
24
|
-
ExternalRegistryConfig,
|
|
25
|
-
load_external_environments,
|
|
26
|
-
)
|
|
27
|
-
from synth_ai.environments.service.registry import list_supported_env_types, register_environment
|
|
28
30
|
|
|
29
31
|
# Configure logging with more detail
|
|
30
32
|
logging.basicConfig(
|
|
@@ -38,11 +40,8 @@ logger = logging.getLogger(__name__)
|
|
|
38
40
|
logging.getLogger("uvicorn.access").setLevel(logging.INFO)
|
|
39
41
|
|
|
40
42
|
# Register built-in environments at import time
|
|
41
|
-
import synth_ai.environments.examples.crafter_classic.environment as cc
|
|
42
43
|
|
|
43
44
|
register_environment("CrafterClassic", cc.CrafterClassicEnvironment)
|
|
44
|
-
import synth_ai.environments.examples.crafter_custom.environment as ccustom
|
|
45
|
-
|
|
46
45
|
register_environment("CrafterCustom", ccustom.CrafterCustomEnvironment)
|
|
47
46
|
|
|
48
47
|
# Register Wordle example environment
|
|
@@ -97,15 +97,12 @@ def create_task_instance_for_environment(
|
|
|
97
97
|
task.initial_engine_snapshot["seed"] = config["seed"]
|
|
98
98
|
|
|
99
99
|
# For CrafterClassic, also handle difficulty
|
|
100
|
-
if env_name == "CrafterClassic" and config:
|
|
101
|
-
|
|
102
|
-
task.initial_engine_snapshot["difficulty"] = config["difficulty"]
|
|
100
|
+
if env_name == "CrafterClassic" and config and "difficulty" in config:
|
|
101
|
+
task.initial_engine_snapshot["difficulty"] = config["difficulty"]
|
|
103
102
|
|
|
104
103
|
# For MiniGrid, handle environment selection
|
|
105
|
-
if env_name == "MiniGrid" and config:
|
|
106
|
-
|
|
107
|
-
if "env_name" in config:
|
|
108
|
-
task.initial_engine_snapshot["env_name"] = config["env_name"]
|
|
104
|
+
if env_name == "MiniGrid" and config and "env_name" in config:
|
|
105
|
+
task.initial_engine_snapshot["env_name"] = config["env_name"]
|
|
109
106
|
|
|
110
107
|
return task
|
|
111
108
|
|
|
@@ -951,7 +948,9 @@ async def register_environment_api(request: RegisterEnvironmentRequest) -> dict[
|
|
|
951
948
|
) from e
|
|
952
949
|
except Exception as e:
|
|
953
950
|
logger.error(f"Failed to register environment {request.name}: {e}")
|
|
954
|
-
raise HTTPException(
|
|
951
|
+
raise HTTPException(
|
|
952
|
+
status_code=500, detail=f"Failed to register environment: {str(e)}"
|
|
953
|
+
) from e
|
|
955
954
|
|
|
956
955
|
|
|
957
956
|
@api_router.delete("/registry/environments/{env_name}")
|
|
@@ -984,7 +983,9 @@ async def unregister_environment_api(env_name: str) -> dict[str, Any]:
|
|
|
984
983
|
|
|
985
984
|
except Exception as e:
|
|
986
985
|
logger.error(f"Failed to unregister environment {env_name}: {e}")
|
|
987
|
-
raise HTTPException(
|
|
986
|
+
raise HTTPException(
|
|
987
|
+
status_code=500, detail=f"Failed to unregister environment: {str(e)}"
|
|
988
|
+
) from e
|
|
988
989
|
|
|
989
990
|
|
|
990
991
|
@api_router.get("/registry/environments")
|
|
@@ -29,13 +29,12 @@ class RangeFilter(TaskInstanceMetadataFilter):
|
|
|
29
29
|
# If the attribute doesn't exist on the metadata, it can't be in range.
|
|
30
30
|
return False
|
|
31
31
|
|
|
32
|
-
if not isinstance(instance_value,
|
|
32
|
+
if not isinstance(instance_value, int | float):
|
|
33
33
|
# If the attribute is not a number, it can't be in a numerical range.
|
|
34
34
|
# Or, we could raise an error, depending on desired strictness.
|
|
35
35
|
return False
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return True
|
|
37
|
+
return not (
|
|
38
|
+
(self.min_val is not None and instance_value < self.min_val)
|
|
39
|
+
or (self.max_val is not None and instance_value > self.max_val)
|
|
40
|
+
)
|
|
@@ -54,11 +54,10 @@ class RangeFilter(TaskInstanceMetadataFilter):
|
|
|
54
54
|
|
|
55
55
|
def __call__(self, instance: TaskInstance) -> bool:
|
|
56
56
|
value = getattr(instance.metadata, self.key, None)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return True
|
|
57
|
+
return not (
|
|
58
|
+
(self.min_value is not None and (value is None or value < self.min_value))
|
|
59
|
+
or (self.max_value is not None and (value is None or value > self.max_value))
|
|
60
|
+
)
|
|
62
61
|
|
|
63
62
|
|
|
64
63
|
def make_taskset(
|
synth_ai/evals/base.py
CHANGED
synth_ai/handshake.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
2
4
|
import os
|
|
3
5
|
import time
|
|
4
6
|
import webbrowser
|
|
5
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
6
8
|
from urllib.parse import urljoin, urlsplit, urlunsplit
|
|
7
9
|
|
|
8
10
|
import requests
|
|
@@ -43,7 +45,7 @@ def _split_origin(origin: str) -> tuple[str, str]:
|
|
|
43
45
|
return bare, path
|
|
44
46
|
|
|
45
47
|
|
|
46
|
-
def _ensure_verification_uri(data:
|
|
48
|
+
def _ensure_verification_uri(data: dict[str, Any], base_with_path: str) -> None:
|
|
47
49
|
uri = data.get("verification_uri")
|
|
48
50
|
if not isinstance(uri, str) or not uri:
|
|
49
51
|
return
|
|
@@ -52,7 +54,7 @@ def _ensure_verification_uri(data: Dict[str, Any], base_with_path: str) -> None:
|
|
|
52
54
|
data["verification_uri"] = urljoin(base_with_path.rstrip("/") + "/", uri.lstrip("/"))
|
|
53
55
|
|
|
54
56
|
|
|
55
|
-
def start_handshake_session(origin: str | None = None) ->
|
|
57
|
+
def start_handshake_session(origin: str | None = None) -> tuple[str, str, int, int]:
|
|
56
58
|
base = (origin or _origin()).rstrip("/")
|
|
57
59
|
api_origin, _ = _split_origin(base)
|
|
58
60
|
url = urljoin(api_origin.rstrip("/") + "/", "api/sdk/handshake/init")
|
|
@@ -72,7 +74,9 @@ def start_handshake_session(origin: str | None = None) -> Tuple[str, str, int, i
|
|
|
72
74
|
)
|
|
73
75
|
|
|
74
76
|
|
|
75
|
-
def poll_handshake_token(
|
|
77
|
+
def poll_handshake_token(
|
|
78
|
+
device_code: str, origin: str | None = None, *, timeout_s: int | None = None
|
|
79
|
+
) -> dict[str, Any]:
|
|
76
80
|
base = (origin or _origin()).rstrip("/")
|
|
77
81
|
api_origin, _ = _split_origin(base)
|
|
78
82
|
url = urljoin(api_origin.rstrip("/") + "/", "api/sdk/handshake/token")
|
|
@@ -82,7 +86,7 @@ def poll_handshake_token(device_code: str, origin: str | None = None, *, timeout
|
|
|
82
86
|
raise HandshakeError("handshake timed out")
|
|
83
87
|
try:
|
|
84
88
|
r = requests.post(url, json={"device_code": device_code}, timeout=10)
|
|
85
|
-
except Exception
|
|
89
|
+
except Exception:
|
|
86
90
|
time.sleep(2)
|
|
87
91
|
continue
|
|
88
92
|
if r.status_code == 200:
|
|
@@ -98,10 +102,8 @@ def poll_handshake_token(device_code: str, origin: str | None = None, *, timeout
|
|
|
98
102
|
time.sleep(2)
|
|
99
103
|
|
|
100
104
|
|
|
101
|
-
def run_handshake(origin: str | None = None) ->
|
|
105
|
+
def run_handshake(origin: str | None = None) -> dict[str, Any]:
|
|
102
106
|
device_code, verification_uri, expires_in, interval = start_handshake_session(origin)
|
|
103
|
-
|
|
107
|
+
with contextlib.suppress(Exception):
|
|
104
108
|
webbrowser.open(verification_uri)
|
|
105
|
-
except Exception:
|
|
106
|
-
pass
|
|
107
109
|
return poll_handshake_token(device_code, origin, timeout_s=expires_in)
|
synth_ai/http.py
CHANGED
|
@@ -18,7 +18,7 @@ except Exception:
|
|
|
18
18
|
_client_path = _here.parent / "http_client.py"
|
|
19
19
|
_spec = _ilu.spec_from_file_location("http_client", str(_client_path))
|
|
20
20
|
if not _spec or not _spec.loader:
|
|
21
|
-
raise ImportError("Could not load http_client module")
|
|
21
|
+
raise ImportError("Could not load http_client module") from None
|
|
22
22
|
_mod = _ilu.module_from_spec(_spec)
|
|
23
23
|
_spec.loader.exec_module(_mod)
|
|
24
24
|
_sys.modules["synth_ai.http_client"] = _mod
|
synth_ai/http_client.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import os
|
|
4
5
|
from dataclasses import dataclass
|
|
5
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
import aiohttp
|
|
8
9
|
|
|
@@ -27,11 +28,18 @@ class AsyncHttpClient:
|
|
|
27
28
|
self._base_url = base_url.rstrip("/")
|
|
28
29
|
self._api_key = api_key
|
|
29
30
|
self._timeout = aiohttp.ClientTimeout(total=timeout)
|
|
30
|
-
self._session:
|
|
31
|
+
self._session: aiohttp.ClientSession | None = None
|
|
31
32
|
|
|
32
|
-
async def __aenter__(self) ->
|
|
33
|
+
async def __aenter__(self) -> AsyncHttpClient:
|
|
33
34
|
if self._session is None:
|
|
34
35
|
headers = {"authorization": f"Bearer {self._api_key}"}
|
|
36
|
+
# Optional dev overrides for user/org context
|
|
37
|
+
user_id = os.getenv("SYNTH_USER_ID") or os.getenv("X_USER_ID") or os.getenv("USER_ID")
|
|
38
|
+
if user_id:
|
|
39
|
+
headers["X-User-ID"] = user_id
|
|
40
|
+
org_id = os.getenv("SYNTH_ORG_ID") or os.getenv("X_ORG_ID") or os.getenv("ORG_ID")
|
|
41
|
+
if org_id:
|
|
42
|
+
headers["X-Org-ID"] = org_id
|
|
35
43
|
self._session = aiohttp.ClientSession(headers=headers, timeout=self._timeout)
|
|
36
44
|
return self
|
|
37
45
|
|
|
@@ -48,30 +56,50 @@ class AsyncHttpClient:
|
|
|
48
56
|
path = path[4:] # Remove leading /api
|
|
49
57
|
return f"{self._base_url}/{path.lstrip('/')}"
|
|
50
58
|
|
|
51
|
-
async def get(
|
|
59
|
+
async def get(
|
|
60
|
+
self,
|
|
61
|
+
path: str,
|
|
62
|
+
*,
|
|
63
|
+
params: dict[str, Any] | None = None,
|
|
64
|
+
headers: dict[str, str] | None = None,
|
|
65
|
+
) -> Any:
|
|
52
66
|
url = self._abs(path)
|
|
53
67
|
assert self._session is not None, "AsyncHttpClient must be used as an async context manager"
|
|
54
68
|
async with self._session.get(url, params=params, headers=headers) as resp:
|
|
55
69
|
return await self._handle_response(resp, url)
|
|
56
70
|
|
|
57
|
-
async def post_json(
|
|
71
|
+
async def post_json(
|
|
72
|
+
self, path: str, *, json: dict[str, Any], headers: dict[str, str] | None = None
|
|
73
|
+
) -> Any:
|
|
58
74
|
url = self._abs(path)
|
|
59
75
|
assert self._session is not None, "AsyncHttpClient must be used as an async context manager"
|
|
60
76
|
async with self._session.post(url, json=json, headers=headers) as resp:
|
|
61
77
|
return await self._handle_response(resp, url)
|
|
62
78
|
|
|
63
|
-
async def post_multipart(
|
|
79
|
+
async def post_multipart(
|
|
80
|
+
self,
|
|
81
|
+
path: str,
|
|
82
|
+
*,
|
|
83
|
+
data: dict[str, Any],
|
|
84
|
+
files: dict[str, tuple[str, bytes, str | None]],
|
|
85
|
+
headers: dict[str, str] | None = None,
|
|
86
|
+
) -> Any:
|
|
64
87
|
url = self._abs(path)
|
|
65
88
|
assert self._session is not None, "AsyncHttpClient must be used as an async context manager"
|
|
66
89
|
form = aiohttp.FormData()
|
|
67
90
|
for k, v in data.items():
|
|
68
91
|
form.add_field(k, str(v))
|
|
69
92
|
for field, (filename, content, content_type) in files.items():
|
|
70
|
-
form.add_field(
|
|
93
|
+
form.add_field(
|
|
94
|
+
field,
|
|
95
|
+
content,
|
|
96
|
+
filename=filename,
|
|
97
|
+
content_type=content_type or "application/octet-stream",
|
|
98
|
+
)
|
|
71
99
|
async with self._session.post(url, data=form, headers=headers) as resp:
|
|
72
100
|
return await self._handle_response(resp, url)
|
|
73
101
|
|
|
74
|
-
async def delete(self, path: str, *, headers:
|
|
102
|
+
async def delete(self, path: str, *, headers: dict[str, str] | None = None) -> Any:
|
|
75
103
|
url = self._abs(path)
|
|
76
104
|
assert self._session is not None, "AsyncHttpClient must be used as an async context manager"
|
|
77
105
|
async with self._session.delete(url, headers=headers) as resp:
|
|
@@ -95,10 +123,14 @@ class AsyncHttpClient:
|
|
|
95
123
|
detail = await resp.json()
|
|
96
124
|
except Exception:
|
|
97
125
|
detail = None
|
|
98
|
-
raise HTTPError(
|
|
126
|
+
raise HTTPError(
|
|
127
|
+
status=resp.status,
|
|
128
|
+
url=url,
|
|
129
|
+
message="request_failed",
|
|
130
|
+
body_snippet=body_snippet,
|
|
131
|
+
detail=detail,
|
|
132
|
+
)
|
|
99
133
|
|
|
100
134
|
|
|
101
135
|
async def sleep(seconds: float) -> None:
|
|
102
136
|
await asyncio.sleep(seconds)
|
|
103
|
-
|
|
104
|
-
|
synth_ai/inference/__init__.py
CHANGED
synth_ai/inference/client.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from synth_ai.api.models.supported import (
|
|
6
|
+
UnsupportedModelError,
|
|
7
|
+
normalize_model_identifier,
|
|
8
|
+
)
|
|
4
9
|
|
|
5
10
|
from ..http import AsyncHttpClient
|
|
6
11
|
|
|
@@ -11,10 +16,19 @@ class InferenceClient:
|
|
|
11
16
|
self._api_key = api_key
|
|
12
17
|
self._timeout = timeout
|
|
13
18
|
|
|
14
|
-
async def create_chat_completion(
|
|
15
|
-
|
|
19
|
+
async def create_chat_completion(
|
|
20
|
+
self, *, model: str, messages: list[dict], **kwargs: Any
|
|
21
|
+
) -> dict[str, Any]:
|
|
22
|
+
try:
|
|
23
|
+
normalized_model = normalize_model_identifier(model)
|
|
24
|
+
except UnsupportedModelError as exc:
|
|
25
|
+
raise ValueError(str(exc)) from exc
|
|
26
|
+
|
|
27
|
+
body: dict[str, Any] = {"model": normalized_model, "messages": messages}
|
|
16
28
|
body.update(kwargs)
|
|
29
|
+
# Backend now expects an explicit thinking_budget; provide a sensible default if omitted
|
|
30
|
+
if "thinking_budget" not in body:
|
|
31
|
+
body["thinking_budget"] = 256
|
|
17
32
|
async with AsyncHttpClient(self._base_url, self._api_key, timeout=self._timeout) as http:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
33
|
+
# Route through backend inference proxy to Modal
|
|
34
|
+
return await http.post_json("/api/inference/v1/chat/completions", json=body)
|