synth-ai 0.2.9.dev5__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 +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.dev6.dist-info/METADATA +191 -0
- {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/RECORD +291 -262
- {synth_ai-0.2.9.dev5.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
- 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/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.dev5.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.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import contextlib
|
|
4
5
|
import logging
|
|
5
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
import httpx
|
|
8
9
|
|
|
@@ -11,22 +12,24 @@ logger = logging.getLogger(__name__)
|
|
|
11
12
|
|
|
12
13
|
class OpenAIClient:
|
|
13
14
|
"""Async HTTP client for OpenAI-compatible inference servers (vLLM)."""
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
def __init__(
|
|
16
17
|
self,
|
|
17
18
|
base_url: str,
|
|
18
|
-
api_key:
|
|
19
|
+
api_key: str | None = None,
|
|
19
20
|
timeout_s: float = 120.0,
|
|
20
21
|
) -> None:
|
|
21
22
|
self.base_url = base_url.rstrip("/")
|
|
22
23
|
self.api_key = api_key
|
|
23
24
|
self.timeout_s = timeout_s
|
|
24
25
|
self.headers = {}
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
if api_key:
|
|
27
28
|
self.headers["Authorization"] = f"Bearer {api_key}"
|
|
28
29
|
|
|
29
|
-
def _fix_model_parameters(
|
|
30
|
+
def _fix_model_parameters(
|
|
31
|
+
self, request: dict[str, Any], target_url: str | None = None
|
|
32
|
+
) -> dict[str, Any]:
|
|
30
33
|
"""
|
|
31
34
|
Fix parameter compatibility for newer OpenAI models.
|
|
32
35
|
|
|
@@ -75,7 +78,9 @@ class OpenAIClient:
|
|
|
75
78
|
if "max_tokens" in fixed_request:
|
|
76
79
|
if "max_completion_tokens" not in fixed_request:
|
|
77
80
|
fixed_request["max_completion_tokens"] = fixed_request.pop("max_tokens")
|
|
78
|
-
logger.info(
|
|
81
|
+
logger.info(
|
|
82
|
+
f"Converted max_tokens to max_completion_tokens for model {model}"
|
|
83
|
+
)
|
|
79
84
|
else:
|
|
80
85
|
fixed_request.pop("max_tokens")
|
|
81
86
|
logger.info(f"Removed conflicting max_tokens parameter for model {model}")
|
|
@@ -87,9 +92,25 @@ class OpenAIClient:
|
|
|
87
92
|
try:
|
|
88
93
|
tools = fixed_request.get("tools")
|
|
89
94
|
if isinstance(tools, list) and tools:
|
|
95
|
+
# Choose the first provided function name from tools schema (e.g., run_command)
|
|
96
|
+
func_name = None
|
|
97
|
+
for t in tools:
|
|
98
|
+
try:
|
|
99
|
+
cand = None
|
|
100
|
+
if isinstance(t, dict):
|
|
101
|
+
f = t.get("function")
|
|
102
|
+
if isinstance(f, dict):
|
|
103
|
+
cand = f.get("name")
|
|
104
|
+
if isinstance(cand, str) and cand:
|
|
105
|
+
func_name = cand
|
|
106
|
+
break
|
|
107
|
+
except Exception:
|
|
108
|
+
continue
|
|
109
|
+
if not func_name:
|
|
110
|
+
func_name = "run_command"
|
|
90
111
|
fixed_request["tool_choice"] = {
|
|
91
112
|
"type": "function",
|
|
92
|
-
"function": {"name":
|
|
113
|
+
"function": {"name": func_name},
|
|
93
114
|
}
|
|
94
115
|
fixed_request["parallel_tool_calls"] = False
|
|
95
116
|
except Exception:
|
|
@@ -99,11 +120,11 @@ class OpenAIClient:
|
|
|
99
120
|
|
|
100
121
|
async def generate(
|
|
101
122
|
self,
|
|
102
|
-
request:
|
|
103
|
-
base_url:
|
|
104
|
-
timeout_s:
|
|
105
|
-
extra_headers:
|
|
106
|
-
) ->
|
|
123
|
+
request: dict[str, Any],
|
|
124
|
+
base_url: str | None = None,
|
|
125
|
+
timeout_s: float | None = None,
|
|
126
|
+
extra_headers: dict[str, str] | None = None,
|
|
127
|
+
) -> dict[str, Any]:
|
|
107
128
|
"""
|
|
108
129
|
Send a chat completion request to the inference server.
|
|
109
130
|
|
|
@@ -131,21 +152,20 @@ class OpenAIClient:
|
|
|
131
152
|
logger.info(f"Inference POST target: {url}")
|
|
132
153
|
if extra_headers:
|
|
133
154
|
logger.info(f"Extra headers: {extra_headers}")
|
|
134
|
-
|
|
135
|
-
keys_preview = sorted(
|
|
155
|
+
with contextlib.suppress(Exception):
|
|
156
|
+
keys_preview = sorted(processed_request.keys())
|
|
136
157
|
logger.info(f"Request keys: {keys_preview}")
|
|
137
|
-
except Exception:
|
|
138
|
-
pass
|
|
139
158
|
|
|
140
159
|
# Final hard-guard for OpenAI: ensure unsupported field is not present
|
|
141
160
|
try:
|
|
142
|
-
if "openai" in url.lower():
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
logger.info("Removed stop_after_tool_calls for OpenAI request")
|
|
161
|
+
if "openai" in url.lower() and "stop_after_tool_calls" in processed_request:
|
|
162
|
+
processed_request.pop("stop_after_tool_calls", None)
|
|
163
|
+
logger.info("Removed stop_after_tool_calls for OpenAI request")
|
|
146
164
|
# Groq-specific requirement: when using JSON mode, one of the messages must contain the word 'json'
|
|
147
165
|
low_url = url.lower()
|
|
148
|
-
if ("groq.com" in low_url or "/openai" in low_url) and isinstance(
|
|
166
|
+
if ("groq.com" in low_url or "/openai" in low_url) and isinstance(
|
|
167
|
+
processed_request, dict
|
|
168
|
+
):
|
|
149
169
|
rf = processed_request.get("response_format")
|
|
150
170
|
rf_type = None
|
|
151
171
|
if isinstance(rf, dict):
|
|
@@ -164,7 +184,9 @@ class OpenAIClient:
|
|
|
164
184
|
# Join any text segments
|
|
165
185
|
parts = []
|
|
166
186
|
for seg in content:
|
|
167
|
-
if isinstance(seg, dict) and isinstance(
|
|
187
|
+
if isinstance(seg, dict) and isinstance(
|
|
188
|
+
seg.get("text"), str
|
|
189
|
+
):
|
|
168
190
|
parts.append(seg["text"])
|
|
169
191
|
text = "\n".join(parts)
|
|
170
192
|
if isinstance(text, str) and ("json" in text.lower()):
|
|
@@ -174,13 +196,17 @@ class OpenAIClient:
|
|
|
174
196
|
continue
|
|
175
197
|
if not has_json_word:
|
|
176
198
|
try:
|
|
177
|
-
instruction =
|
|
199
|
+
instruction = (
|
|
200
|
+
"Respond in strict JSON only. Output a single valid JSON object."
|
|
201
|
+
)
|
|
178
202
|
if not isinstance(msgs, list):
|
|
179
203
|
msgs = []
|
|
180
204
|
# Prepend a system message to satisfy Groq requirement without changing user intent
|
|
181
205
|
prepend = {"role": "system", "content": instruction}
|
|
182
206
|
processed_request["messages"] = [prepend] + list(msgs)
|
|
183
|
-
logger.info(
|
|
207
|
+
logger.info(
|
|
208
|
+
"Injected JSON-mode system instruction for Groq response_format compliance"
|
|
209
|
+
)
|
|
184
210
|
except Exception:
|
|
185
211
|
pass
|
|
186
212
|
except Exception:
|
|
@@ -194,7 +220,7 @@ class OpenAIClient:
|
|
|
194
220
|
headers=headers,
|
|
195
221
|
)
|
|
196
222
|
response.raise_for_status()
|
|
197
|
-
|
|
223
|
+
|
|
198
224
|
# Rich response diagnostics
|
|
199
225
|
content_type = response.headers.get("content-type")
|
|
200
226
|
body_text = response.text
|
|
@@ -203,12 +229,14 @@ class OpenAIClient:
|
|
|
203
229
|
)
|
|
204
230
|
if body_text:
|
|
205
231
|
preview_len = min(800, len(body_text))
|
|
206
|
-
logger.info(
|
|
232
|
+
logger.info(
|
|
233
|
+
f"Inference response preview ({preview_len} bytes): {body_text[:preview_len]}"
|
|
234
|
+
)
|
|
207
235
|
|
|
208
236
|
result = response.json()
|
|
209
237
|
logger.info(f"Inference response parsed_type={type(result).__name__}")
|
|
210
238
|
return result
|
|
211
|
-
|
|
239
|
+
|
|
212
240
|
except httpx.TimeoutException:
|
|
213
241
|
logger.error(f"Request to {url} timed out after {timeout}s")
|
|
214
242
|
raise
|
|
@@ -217,12 +245,14 @@ class OpenAIClient:
|
|
|
217
245
|
text = e.response.text if e.response is not None else str(e)
|
|
218
246
|
# Log full body for debugging remote failures
|
|
219
247
|
try:
|
|
220
|
-
logger.error(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
248
|
+
logger.error(
|
|
249
|
+
{
|
|
250
|
+
"openai_http_error": True,
|
|
251
|
+
"status": status,
|
|
252
|
+
"url": url,
|
|
253
|
+
"body": text,
|
|
254
|
+
}
|
|
255
|
+
)
|
|
226
256
|
except Exception:
|
|
227
257
|
logger.error(f"HTTP error from {url}: {status} - {text}")
|
|
228
258
|
# For 4xx/5xx, print full sanitized request to aid debugging (especially Groq 400s)
|
|
@@ -230,13 +260,15 @@ class OpenAIClient:
|
|
|
230
260
|
redacted_headers = dict(headers)
|
|
231
261
|
if "Authorization" in redacted_headers:
|
|
232
262
|
redacted_headers["Authorization"] = "***REDACTED***"
|
|
233
|
-
logger.error(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
263
|
+
logger.error(
|
|
264
|
+
{
|
|
265
|
+
"request_debug": True,
|
|
266
|
+
"status": status,
|
|
267
|
+
"target": url,
|
|
268
|
+
"headers": redacted_headers,
|
|
269
|
+
"payload": processed_request,
|
|
270
|
+
}
|
|
271
|
+
)
|
|
240
272
|
except Exception:
|
|
241
273
|
pass
|
|
242
274
|
# Special case: token budget exceeded (OpenAI-compatible error schema)
|
|
@@ -266,27 +298,42 @@ class OpenAIClient:
|
|
|
266
298
|
processed_request.pop(k, None)
|
|
267
299
|
# Force structured tool choice
|
|
268
300
|
if processed_request.get("tool_choice") == "required":
|
|
269
|
-
func_name = "
|
|
301
|
+
func_name = "run_command"
|
|
270
302
|
try:
|
|
271
303
|
tools_arr = processed_request.get("tools") or []
|
|
272
304
|
if isinstance(tools_arr, list) and tools_arr:
|
|
273
|
-
f =
|
|
274
|
-
|
|
305
|
+
f = (
|
|
306
|
+
tools_arr[0].get("function")
|
|
307
|
+
if isinstance(tools_arr[0], dict)
|
|
308
|
+
else None
|
|
309
|
+
)
|
|
310
|
+
cand = (
|
|
311
|
+
(f or {}).get("name")
|
|
312
|
+
if isinstance(f, dict)
|
|
313
|
+
else None
|
|
314
|
+
)
|
|
275
315
|
if isinstance(cand, str) and cand:
|
|
276
316
|
func_name = cand
|
|
277
317
|
except Exception:
|
|
278
318
|
pass
|
|
279
|
-
processed_request["tool_choice"] = {
|
|
319
|
+
processed_request["tool_choice"] = {
|
|
320
|
+
"type": "function",
|
|
321
|
+
"function": {"name": func_name},
|
|
322
|
+
}
|
|
280
323
|
processed_request["parallel_tool_calls"] = False
|
|
281
|
-
logger.warning(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
324
|
+
logger.warning(
|
|
325
|
+
{
|
|
326
|
+
"token_budget_recovery": True,
|
|
327
|
+
"messages_tokens": messages_tokens,
|
|
328
|
+
"model_limit": model_limit,
|
|
329
|
+
"retry_max_tokens": new_max,
|
|
330
|
+
}
|
|
331
|
+
)
|
|
287
332
|
# Retry once with reduced budget
|
|
288
333
|
async with httpx.AsyncClient(timeout=timeout) as client2:
|
|
289
|
-
r2 = await client2.post(
|
|
334
|
+
r2 = await client2.post(
|
|
335
|
+
url, json=processed_request, headers=headers
|
|
336
|
+
)
|
|
290
337
|
r2.raise_for_status()
|
|
291
338
|
return r2.json()
|
|
292
339
|
except Exception:
|
|
@@ -302,14 +349,17 @@ class OpenAIClient:
|
|
|
302
349
|
err = e.response.json()
|
|
303
350
|
except Exception:
|
|
304
351
|
err = {"error": "unprocessable", "detail": (text or "")[:200]}
|
|
305
|
-
logger.warning(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
352
|
+
logger.warning(
|
|
353
|
+
{
|
|
354
|
+
"inference_422_recovered": True,
|
|
355
|
+
"detail": err,
|
|
356
|
+
}
|
|
357
|
+
)
|
|
309
358
|
except Exception:
|
|
310
359
|
pass
|
|
311
360
|
# Return a minimal OpenAI-compatible response with no tool_calls/content
|
|
312
361
|
import time as _t
|
|
362
|
+
|
|
313
363
|
return {
|
|
314
364
|
"id": f"cmpl-{int(_t.time())}",
|
|
315
365
|
"object": "chat.completion",
|
|
@@ -328,25 +378,25 @@ class OpenAIClient:
|
|
|
328
378
|
except Exception as e:
|
|
329
379
|
logger.error(f"Unexpected error calling {url}: {e}")
|
|
330
380
|
raise
|
|
331
|
-
|
|
381
|
+
|
|
332
382
|
async def check_health(
|
|
333
383
|
self,
|
|
334
|
-
base_url:
|
|
335
|
-
timeout_s:
|
|
336
|
-
) ->
|
|
384
|
+
base_url: str | None = None,
|
|
385
|
+
timeout_s: float | None = None,
|
|
386
|
+
) -> dict[str, Any]:
|
|
337
387
|
"""
|
|
338
388
|
Check if the inference service is healthy.
|
|
339
|
-
|
|
389
|
+
|
|
340
390
|
Args:
|
|
341
391
|
base_url: Override base URL for this request
|
|
342
392
|
timeout_s: Override timeout for this request
|
|
343
|
-
|
|
393
|
+
|
|
344
394
|
Returns:
|
|
345
395
|
Health status dict with 'status' field
|
|
346
396
|
"""
|
|
347
397
|
url = (base_url or self.base_url).rstrip("/") + "/health"
|
|
348
398
|
timeout = timeout_s or 10.0
|
|
349
|
-
|
|
399
|
+
|
|
350
400
|
try:
|
|
351
401
|
async with httpx.AsyncClient(timeout=timeout) as client:
|
|
352
402
|
response = await client.get(url, headers=self.headers)
|
|
@@ -364,19 +414,19 @@ class OpenAIClient:
|
|
|
364
414
|
return {"status": "unhealthy", "error": str(e)}
|
|
365
415
|
except Exception as e:
|
|
366
416
|
return {"status": "unhealthy", "error": str(e)}
|
|
367
|
-
|
|
417
|
+
|
|
368
418
|
async def generate_with_retries(
|
|
369
419
|
self,
|
|
370
|
-
request:
|
|
371
|
-
base_url:
|
|
372
|
-
timeout_s:
|
|
420
|
+
request: dict[str, Any],
|
|
421
|
+
base_url: str | None = None,
|
|
422
|
+
timeout_s: float | None = None,
|
|
373
423
|
max_retries: int = 4,
|
|
374
424
|
backoff_factor: float = 2.0,
|
|
375
|
-
extra_headers:
|
|
376
|
-
) ->
|
|
425
|
+
extra_headers: dict[str, str] | None = None,
|
|
426
|
+
) -> dict[str, Any]:
|
|
377
427
|
"""
|
|
378
428
|
Generate with exponential backoff retries for transient errors.
|
|
379
|
-
|
|
429
|
+
|
|
380
430
|
Args:
|
|
381
431
|
request: OpenAI-compatible chat completion request
|
|
382
432
|
base_url: Override base URL
|
|
@@ -384,13 +434,13 @@ class OpenAIClient:
|
|
|
384
434
|
max_retries: Maximum number of retry attempts
|
|
385
435
|
backoff_factor: Exponential backoff multiplier
|
|
386
436
|
extra_headers: Additional headers to include (e.g., X-Policy-Name)
|
|
387
|
-
|
|
437
|
+
|
|
388
438
|
Returns:
|
|
389
439
|
OpenAI-compatible chat completion response
|
|
390
440
|
"""
|
|
391
441
|
last_error = None
|
|
392
442
|
wait_time = 1.0
|
|
393
|
-
|
|
443
|
+
|
|
394
444
|
for attempt in range(max_retries + 1):
|
|
395
445
|
try:
|
|
396
446
|
# Apply parameter fixes to the request
|
|
@@ -417,7 +467,9 @@ class OpenAIClient:
|
|
|
417
467
|
retry_after = response_data.get("retry_after", 1)
|
|
418
468
|
# Use the suggested retry_after time instead of exponential backoff for overload
|
|
419
469
|
wait_time = max(wait_time, float(retry_after))
|
|
420
|
-
logger.warning(
|
|
470
|
+
logger.warning(
|
|
471
|
+
f"Inference service overloaded (400). {response_data} Retrying after {wait_time}s..."
|
|
472
|
+
)
|
|
421
473
|
else:
|
|
422
474
|
# This is a different type of 400 error, don't retry
|
|
423
475
|
try:
|
|
@@ -428,13 +480,15 @@ class OpenAIClient:
|
|
|
428
480
|
redacted_headers["Authorization"] = "***REDACTED***"
|
|
429
481
|
except Exception:
|
|
430
482
|
redacted_headers = {}
|
|
431
|
-
logger.error(
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
483
|
+
logger.error(
|
|
484
|
+
{
|
|
485
|
+
"non_overload_400": True,
|
|
486
|
+
"target": (base_url or self.base_url),
|
|
487
|
+
"payload": processed_request,
|
|
488
|
+
"headers": redacted_headers,
|
|
489
|
+
"body": e.response.text if e.response is not None else None,
|
|
490
|
+
}
|
|
491
|
+
)
|
|
438
492
|
except Exception:
|
|
439
493
|
pass
|
|
440
494
|
raise RuntimeError(
|
|
@@ -442,14 +496,14 @@ class OpenAIClient:
|
|
|
442
496
|
) from e
|
|
443
497
|
except Exception:
|
|
444
498
|
# If we can't parse the response, don't retry 400 errors
|
|
445
|
-
|
|
446
|
-
logger.error(
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
499
|
+
with contextlib.suppress(Exception):
|
|
500
|
+
logger.error(
|
|
501
|
+
{
|
|
502
|
+
"non_overload_400_unparsed": True,
|
|
503
|
+
"target": (base_url or self.base_url),
|
|
504
|
+
"payload": processed_request,
|
|
505
|
+
}
|
|
506
|
+
)
|
|
453
507
|
raise RuntimeError(
|
|
454
508
|
f"Inference 400 response (unparsed): {e.response.text if e.response is not None else 'Bad Request'}"
|
|
455
509
|
) from e
|
|
@@ -472,7 +526,7 @@ class OpenAIClient:
|
|
|
472
526
|
)
|
|
473
527
|
except httpx.TimeoutException as e:
|
|
474
528
|
last_error = e
|
|
475
|
-
|
|
529
|
+
|
|
476
530
|
if attempt < max_retries:
|
|
477
531
|
logger.warning(
|
|
478
532
|
f"Inference request failed (attempt {attempt + 1}/{max_retries + 1}), "
|
|
@@ -480,21 +534,21 @@ class OpenAIClient:
|
|
|
480
534
|
)
|
|
481
535
|
await asyncio.sleep(wait_time)
|
|
482
536
|
wait_time *= backoff_factor
|
|
483
|
-
|
|
537
|
+
|
|
484
538
|
raise last_error
|
|
485
539
|
|
|
486
540
|
|
|
487
541
|
def create_inference_client(
|
|
488
542
|
task_app: Any,
|
|
489
|
-
api_key:
|
|
543
|
+
api_key: str | None = None,
|
|
490
544
|
) -> OpenAIClient:
|
|
491
545
|
"""
|
|
492
546
|
Create an inference client using TaskApp configuration.
|
|
493
|
-
|
|
547
|
+
|
|
494
548
|
Args:
|
|
495
549
|
task_app: TaskApp instance with vllm_base_url
|
|
496
550
|
api_key: Optional API key for authentication
|
|
497
|
-
|
|
551
|
+
|
|
498
552
|
Returns:
|
|
499
553
|
Configured OpenAIClient instance
|
|
500
554
|
"""
|
|
@@ -502,10 +556,62 @@ def create_inference_client(
|
|
|
502
556
|
if api_key is None:
|
|
503
557
|
try:
|
|
504
558
|
import os as _os # local import to avoid module-level side effects
|
|
559
|
+
|
|
505
560
|
api_key = _os.getenv("OPENAI_API_KEY") or getattr(task_app, "openai_api_key", None)
|
|
506
561
|
except Exception:
|
|
507
562
|
api_key = None
|
|
508
563
|
|
|
564
|
+
import json as _json
|
|
565
|
+
import os as _os
|
|
566
|
+
import time as _time
|
|
567
|
+
|
|
568
|
+
if _os.getenv("SYNTH_FAKE_INFERENCE", "").strip():
|
|
569
|
+
|
|
570
|
+
class _DummyClient:
|
|
571
|
+
async def generate_with_retries(
|
|
572
|
+
self,
|
|
573
|
+
request: dict[str, Any],
|
|
574
|
+
base_url: str | None = None,
|
|
575
|
+
max_retries: int = 0,
|
|
576
|
+
backoff_factor: float = 1.0,
|
|
577
|
+
extra_headers: dict[str, str] | None = None,
|
|
578
|
+
) -> dict[str, Any]:
|
|
579
|
+
tool_call = {
|
|
580
|
+
"id": "call_dummy",
|
|
581
|
+
"type": "function",
|
|
582
|
+
"function": {
|
|
583
|
+
"name": "interact_many",
|
|
584
|
+
"arguments": _json.dumps({"actions": ["move_right"]}),
|
|
585
|
+
},
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
"id": f"cmpl-{int(_time.time())}",
|
|
589
|
+
"object": "chat.completion",
|
|
590
|
+
"created": int(_time.time()),
|
|
591
|
+
"model": request.get("model") or "dummy-model",
|
|
592
|
+
"choices": [
|
|
593
|
+
{
|
|
594
|
+
"index": 0,
|
|
595
|
+
"message": {
|
|
596
|
+
"role": "assistant",
|
|
597
|
+
"content": "",
|
|
598
|
+
"tool_calls": [tool_call],
|
|
599
|
+
},
|
|
600
|
+
"finish_reason": "tool_calls",
|
|
601
|
+
}
|
|
602
|
+
],
|
|
603
|
+
"usage": {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15},
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
async def check_health(
|
|
607
|
+
self,
|
|
608
|
+
base_url: str | None = None,
|
|
609
|
+
timeout_s: float | None = None,
|
|
610
|
+
) -> dict[str, Any]:
|
|
611
|
+
return {"status": "ok", "dummy": True}
|
|
612
|
+
|
|
613
|
+
return _DummyClient()
|
|
614
|
+
|
|
509
615
|
return OpenAIClient(
|
|
510
616
|
base_url=task_app.vllm_base_url,
|
|
511
617
|
api_key=api_key,
|
|
@@ -12,7 +12,6 @@ For Modal deployment:
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
14
|
import os
|
|
15
|
-
from typing import Optional
|
|
16
15
|
|
|
17
16
|
import modal
|
|
18
17
|
|
|
@@ -26,7 +25,6 @@ except ImportError:
|
|
|
26
25
|
|
|
27
26
|
from synth_envs_hosted.hosted_app import create_app
|
|
28
27
|
|
|
29
|
-
|
|
30
28
|
# Local development mode
|
|
31
29
|
if __name__ == "__main__":
|
|
32
30
|
import uvicorn
|