synth-ai 0.2.6.dev1__py3-none-any.whl → 0.4.3__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.
- synth_ai/__init__.py +44 -24
- synth_ai/__main__.py +30 -3
- synth_ai/cli/__init__.py +103 -48
- synth_ai/cli/__main__.py +42 -0
- synth_ai/cli/_internal/__init__.py +5 -0
- synth_ai/cli/_internal/modal_wrapper.py +31 -0
- synth_ai/cli/_internal/storage.py +20 -0
- synth_ai/cli/_internal/typer_patch.py +47 -0
- synth_ai/cli/_internal/validate_task_app.py +29 -0
- synth_ai/cli/agents/__init__.py +17 -0
- synth_ai/cli/agents/claude.py +77 -0
- synth_ai/cli/agents/codex.py +265 -0
- synth_ai/cli/agents/opencode.py +253 -0
- synth_ai/cli/commands/__init__.py +18 -0
- synth_ai/cli/commands/artifacts/__init__.py +13 -0
- synth_ai/cli/commands/artifacts/client.py +119 -0
- synth_ai/cli/commands/artifacts/config.py +57 -0
- synth_ai/cli/commands/artifacts/core.py +24 -0
- synth_ai/cli/commands/artifacts/download.py +188 -0
- synth_ai/cli/commands/artifacts/export.py +186 -0
- synth_ai/cli/commands/artifacts/list.py +156 -0
- synth_ai/cli/commands/artifacts/parsing.py +250 -0
- synth_ai/cli/commands/artifacts/show.py +336 -0
- synth_ai/cli/commands/demo/__init__.py +3 -0
- synth_ai/cli/commands/demo/core.py +153 -0
- synth_ai/cli/commands/eval/__init__.py +10 -0
- synth_ai/cli/commands/eval/config.py +338 -0
- synth_ai/cli/commands/eval/core.py +256 -0
- synth_ai/cli/commands/eval/runner.py +704 -0
- synth_ai/cli/commands/eval/validation.py +60 -0
- synth_ai/cli/commands/filter/__init__.py +12 -0
- synth_ai/cli/commands/filter/core.py +424 -0
- synth_ai/cli/commands/filter/errors.py +55 -0
- synth_ai/cli/commands/filter/validation.py +77 -0
- synth_ai/cli/commands/help/__init__.py +185 -0
- synth_ai/cli/commands/help/core.py +72 -0
- synth_ai/cli/commands/scan/__init__.py +19 -0
- synth_ai/cli/commands/scan/cloudflare_scanner.py +403 -0
- synth_ai/cli/commands/scan/core.py +344 -0
- synth_ai/cli/commands/scan/health_checker.py +242 -0
- synth_ai/cli/commands/scan/local_scanner.py +278 -0
- synth_ai/cli/commands/scan/models.py +83 -0
- synth_ai/cli/commands/smoke/__init__.py +7 -0
- synth_ai/cli/commands/smoke/core.py +1428 -0
- synth_ai/cli/commands/status/__init__.py +3 -0
- synth_ai/cli/commands/status/client.py +91 -0
- synth_ai/cli/commands/status/config.py +12 -0
- synth_ai/cli/commands/status/errors.py +11 -0
- synth_ai/cli/commands/status/subcommands/__init__.py +3 -0
- synth_ai/cli/commands/status/subcommands/config.py +13 -0
- synth_ai/cli/commands/status/subcommands/files.py +34 -0
- synth_ai/cli/commands/status/subcommands/jobs.py +51 -0
- synth_ai/cli/commands/status/subcommands/models.py +35 -0
- synth_ai/cli/commands/status/subcommands/runs.py +34 -0
- synth_ai/cli/commands/status/subcommands/session.py +77 -0
- synth_ai/cli/commands/status/subcommands/summary.py +39 -0
- synth_ai/cli/commands/status/subcommands/utils.py +41 -0
- synth_ai/cli/commands/status/utils.py +23 -0
- synth_ai/cli/commands/train/__init__.py +53 -0
- synth_ai/cli/commands/train/core.py +22 -0
- synth_ai/cli/commands/train/errors.py +117 -0
- synth_ai/cli/commands/train/judge_schemas.py +201 -0
- synth_ai/cli/commands/train/judge_validation.py +305 -0
- synth_ai/cli/commands/train/prompt_learning_validation.py +633 -0
- synth_ai/cli/commands/train/validation.py +392 -0
- synth_ai/cli/demo_apps/__init__.py +10 -0
- synth_ai/cli/demo_apps/core/__init__.py +28 -0
- synth_ai/cli/demo_apps/core/cli.py +1735 -0
- synth_ai/cli/demo_apps/crafter/__init__.py +1 -0
- synth_ai/cli/demo_apps/crafter/crafter_fft_4b.toml +55 -0
- synth_ai/cli/demo_apps/crafter/grpo_crafter_task_app.py +186 -0
- synth_ai/cli/demo_apps/crafter/rl_from_base_qwen4b.toml +74 -0
- synth_ai/cli/demo_apps/demo_registry.py +176 -0
- synth_ai/cli/demo_apps/demo_task_apps/__init__.py +7 -0
- synth_ai/{demos → cli/demo_apps}/demo_task_apps/core.py +117 -51
- synth_ai/cli/demo_apps/demo_task_apps/crafter/__init__.py +1 -0
- synth_ai/cli/demo_apps/demo_task_apps/crafter/configs/crafter_fft_4b.toml +53 -0
- synth_ai/cli/demo_apps/demo_task_apps/crafter/configs/rl_from_base_qwen4b.toml +73 -0
- synth_ai/cli/demo_apps/demo_task_apps/crafter/grpo_crafter_task_app.py +185 -0
- synth_ai/cli/demo_apps/demo_task_apps/math/_common.py +16 -0
- synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/app.py +2 -1
- synth_ai/cli/demo_apps/demo_task_apps/math/config.toml +73 -0
- synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/deploy_modal.py +3 -6
- synth_ai/cli/demo_apps/demo_task_apps/math/modal_task_app.py +738 -0
- synth_ai/cli/demo_apps/demo_task_apps/math/task_app_entry.py +39 -0
- synth_ai/cli/demo_apps/math/__init__.py +1 -0
- synth_ai/cli/demo_apps/math/_common.py +16 -0
- synth_ai/cli/demo_apps/math/app.py +38 -0
- synth_ai/cli/demo_apps/math/config.toml +75 -0
- synth_ai/cli/demo_apps/math/deploy_modal.py +54 -0
- synth_ai/cli/demo_apps/math/modal_task_app.py +698 -0
- synth_ai/cli/demo_apps/math/task_app_entry.py +53 -0
- synth_ai/cli/demo_apps/mipro/main.py +271 -0
- synth_ai/cli/demo_apps/mipro/task_app.py +922 -0
- synth_ai/cli/demo_apps/mipro/train_cfg.toml +92 -0
- synth_ai/cli/demos/__init__.py +12 -0
- synth_ai/cli/demos/demo.py +32 -0
- synth_ai/cli/demos/rl_demo.py +254 -0
- synth_ai/cli/deploy.py +216 -0
- synth_ai/cli/infra/__init__.py +14 -0
- synth_ai/cli/{balance.py → infra/balance.py} +21 -3
- synth_ai/cli/infra/mcp.py +35 -0
- synth_ai/cli/infra/modal_app.py +36 -0
- synth_ai/cli/infra/setup.py +69 -0
- synth_ai/cli/infra/status.py +16 -0
- synth_ai/cli/infra/turso.py +77 -0
- synth_ai/cli/lib/__init__.py +10 -0
- synth_ai/cli/lib/agents.py +76 -0
- synth_ai/cli/lib/apps/modal_app.py +101 -0
- synth_ai/cli/lib/apps/task_app.py +642 -0
- synth_ai/cli/lib/bin.py +39 -0
- synth_ai/cli/lib/env.py +375 -0
- synth_ai/cli/lib/errors.py +85 -0
- synth_ai/cli/lib/modal.py +315 -0
- synth_ai/cli/lib/plotting.py +126 -0
- synth_ai/cli/lib/prompt_args.py +39 -0
- synth_ai/cli/lib/prompts.py +284 -0
- synth_ai/cli/lib/sqld.py +122 -0
- synth_ai/cli/lib/task_app_discovery.py +884 -0
- synth_ai/cli/lib/task_app_env.py +295 -0
- synth_ai/cli/lib/train_cfgs.py +300 -0
- synth_ai/cli/lib/tunnel_records.py +207 -0
- synth_ai/cli/local/__init__.py +14 -0
- synth_ai/cli/local/experiment_queue/__init__.py +72 -0
- synth_ai/cli/local/experiment_queue/api_schemas.py +221 -0
- synth_ai/cli/local/experiment_queue/celery_app.py +208 -0
- synth_ai/cli/local/experiment_queue/config.py +128 -0
- synth_ai/cli/local/experiment_queue/config_utils.py +272 -0
- synth_ai/cli/local/experiment_queue/database.py +175 -0
- synth_ai/cli/local/experiment_queue/dispatcher.py +119 -0
- synth_ai/cli/local/experiment_queue/models.py +231 -0
- synth_ai/cli/local/experiment_queue/progress_info.py +160 -0
- synth_ai/cli/local/experiment_queue/results.py +373 -0
- synth_ai/cli/local/experiment_queue/schemas.py +131 -0
- synth_ai/cli/local/experiment_queue/service.py +344 -0
- synth_ai/cli/local/experiment_queue/status.py +372 -0
- synth_ai/cli/local/experiment_queue/status_tracker.py +360 -0
- synth_ai/cli/local/experiment_queue/tasks.py +1984 -0
- synth_ai/cli/local/experiment_queue/trace_storage.py +65 -0
- synth_ai/cli/local/experiment_queue/validation.py +157 -0
- synth_ai/cli/local/session/__init__.py +92 -0
- synth_ai/cli/local/session/client.py +383 -0
- synth_ai/cli/local/session/constants.py +63 -0
- synth_ai/cli/local/session/exceptions.py +105 -0
- synth_ai/cli/local/session/manager.py +139 -0
- synth_ai/cli/local/session/models.py +89 -0
- synth_ai/cli/local/session/query.py +110 -0
- synth_ai/cli/root.py +150 -102
- synth_ai/cli/task_apps/__init__.py +37 -0
- synth_ai/cli/task_apps/commands.py +3145 -0
- synth_ai/cli/task_apps/deploy.py +7 -0
- synth_ai/cli/task_apps/list.py +26 -0
- synth_ai/cli/task_apps/main.py +36 -0
- synth_ai/cli/task_apps/modal_serve.py +11 -0
- synth_ai/cli/task_apps/serve.py +11 -0
- synth_ai/cli/training/__init__.py +8 -0
- synth_ai/cli/training/train.py +5 -0
- synth_ai/cli/training/train_cfg.py +34 -0
- synth_ai/cli/{watch.py → training/watch.py} +13 -18
- synth_ai/cli/turso.py +52 -0
- synth_ai/cli/utils/__init__.py +8 -0
- synth_ai/cli/utils/experiments.py +235 -0
- synth_ai/cli/utils/queue.py +504 -0
- synth_ai/cli/{recent.py → utils/recent.py} +13 -7
- synth_ai/cli/{traces.py → utils/traces.py} +9 -5
- synth_ai/contracts/__init__.py +67 -0
- synth_ai/core/__init__.py +100 -0
- synth_ai/core/_utils/__init__.py +54 -0
- synth_ai/core/_utils/base_url.py +10 -0
- synth_ai/core/_utils/http.py +10 -0
- synth_ai/core/_utils/prompts.py +14 -0
- synth_ai/core/_utils/task_app_state.py +12 -0
- synth_ai/core/_utils/user_config.py +10 -0
- synth_ai/core/apps/common.py +116 -0
- synth_ai/core/auth.py +95 -0
- synth_ai/core/cfgs.py +240 -0
- synth_ai/core/config/__init__.py +16 -0
- synth_ai/core/config/base.py +168 -0
- synth_ai/core/config/resolver.py +89 -0
- synth_ai/core/env.py +231 -0
- synth_ai/core/errors.py +126 -0
- synth_ai/core/http.py +230 -0
- synth_ai/core/integrations/__init__.py +11 -0
- synth_ai/core/integrations/cloudflare.py +1710 -0
- synth_ai/core/integrations/mcp/__init__.py +6 -0
- synth_ai/core/integrations/mcp/__main__.py +8 -0
- synth_ai/core/integrations/mcp/claude.py +36 -0
- synth_ai/core/integrations/mcp/main.py +254 -0
- synth_ai/core/integrations/mcp/setup.py +100 -0
- synth_ai/core/integrations/modal.py +277 -0
- synth_ai/core/json.py +72 -0
- synth_ai/core/log_filter.py +99 -0
- synth_ai/core/logging.py +82 -0
- synth_ai/core/paths.py +107 -0
- synth_ai/core/pricing.py +109 -0
- synth_ai/core/process.py +233 -0
- synth_ai/core/ssl.py +25 -0
- synth_ai/core/storage/__init__.py +71 -0
- synth_ai/core/task_app_state.py +318 -0
- synth_ai/core/telemetry.py +282 -0
- synth_ai/{tracing_v3 → core/tracing_v3}/__init__.py +5 -1
- synth_ai/{tracing_v3 → core/tracing_v3}/abstractions.py +21 -4
- synth_ai/core/tracing_v3/config.py +229 -0
- synth_ai/core/tracing_v3/constants.py +21 -0
- synth_ai/{tracing_v3 → core/tracing_v3}/db_config.py +42 -29
- synth_ai/{tracing_v3 → core/tracing_v3}/decorators.py +80 -45
- synth_ai/{tracing_v3 → core/tracing_v3}/examples/basic_usage.py +15 -9
- synth_ai/{tracing_v3 → core/tracing_v3}/hooks.py +6 -4
- synth_ai/{tracing_v3 → core/tracing_v3}/llm_call_record_helpers.py +161 -61
- synth_ai/{tracing_v3 → core/tracing_v3}/migration_helper.py +1 -2
- synth_ai/{tracing_v3 → core/tracing_v3}/replica_sync.py +12 -7
- synth_ai/core/tracing_v3/serialization.py +130 -0
- synth_ai/{tracing_v3 → core/tracing_v3}/session_tracer.py +88 -21
- synth_ai/{tracing_v3 → core/tracing_v3}/storage/base.py +99 -12
- synth_ai/core/tracing_v3/storage/config.py +109 -0
- synth_ai/{tracing_v3 → core/tracing_v3}/storage/factory.py +11 -9
- synth_ai/{tracing_v3 → core/tracing_v3}/storage/utils.py +15 -11
- synth_ai/core/tracing_v3/trace_utils.py +326 -0
- synth_ai/core/tracing_v3/turso/__init__.py +12 -0
- synth_ai/core/tracing_v3/turso/daemon.py +278 -0
- synth_ai/{tracing_v3 → core/tracing_v3}/turso/models.py +7 -3
- synth_ai/core/tracing_v3/turso/native_manager.py +1385 -0
- synth_ai/{tracing_v3 → core/tracing_v3}/utils.py +5 -4
- synth_ai/core/urls.py +18 -0
- synth_ai/core/user_config.py +137 -0
- synth_ai/core/uvicorn.py +222 -0
- synth_ai/data/__init__.py +83 -0
- synth_ai/data/enums.py +123 -0
- synth_ai/data/rewards.py +152 -0
- synth_ai/data/traces.py +35 -0
- synth_ai/products/__init__.py +6 -0
- synth_ai/products/graph_evolve/__init__.py +46 -0
- synth_ai/products/graph_evolve/client.py +226 -0
- synth_ai/products/graph_evolve/config.py +591 -0
- synth_ai/products/graph_evolve/converters/__init__.py +42 -0
- synth_ai/products/graph_evolve/converters/openai_sft.py +484 -0
- synth_ai/products/graph_evolve/examples/hotpotqa/config.toml +109 -0
- synth_ai/products/graph_evolve/run.py +222 -0
- synth_ai/products/graph_gepa/__init__.py +23 -0
- synth_ai/products/graph_gepa/converters/__init__.py +19 -0
- synth_ai/products/graph_gepa/converters/openai_sft.py +29 -0
- synth_ai/sdk/__init__.py +123 -0
- synth_ai/sdk/api/__init__.py +1 -0
- synth_ai/sdk/api/models/supported.py +514 -0
- synth_ai/sdk/api/research_agent/__init__.py +296 -0
- synth_ai/sdk/api/train/__init__.py +85 -0
- synth_ai/sdk/api/train/builders.py +895 -0
- synth_ai/sdk/api/train/cli.py +2199 -0
- synth_ai/sdk/api/train/config_finder.py +267 -0
- synth_ai/sdk/api/train/configs/__init__.py +65 -0
- synth_ai/sdk/api/train/configs/prompt_learning.py +1706 -0
- synth_ai/sdk/api/train/configs/rl.py +187 -0
- synth_ai/sdk/api/train/configs/sft.py +99 -0
- synth_ai/sdk/api/train/configs/shared.py +81 -0
- synth_ai/sdk/api/train/context_learning.py +312 -0
- synth_ai/sdk/api/train/env_resolver.py +418 -0
- synth_ai/sdk/api/train/graph_validators.py +216 -0
- synth_ai/sdk/api/train/graphgen.py +984 -0
- synth_ai/sdk/api/train/graphgen_models.py +823 -0
- synth_ai/sdk/api/train/graphgen_validators.py +109 -0
- synth_ai/sdk/api/train/local_api.py +10 -0
- synth_ai/sdk/api/train/pollers.py +124 -0
- synth_ai/sdk/api/train/progress/__init__.py +97 -0
- synth_ai/sdk/api/train/progress/dataclasses.py +569 -0
- synth_ai/sdk/api/train/progress/events.py +326 -0
- synth_ai/sdk/api/train/progress/results.py +428 -0
- synth_ai/sdk/api/train/progress/tracker.py +641 -0
- synth_ai/sdk/api/train/prompt_learning.py +469 -0
- synth_ai/sdk/api/train/rl.py +441 -0
- synth_ai/sdk/api/train/sft.py +396 -0
- synth_ai/sdk/api/train/summary.py +522 -0
- synth_ai/sdk/api/train/supported_algos.py +147 -0
- synth_ai/sdk/api/train/task_app.py +351 -0
- synth_ai/sdk/api/train/utils.py +279 -0
- synth_ai/sdk/api/train/validators.py +2424 -0
- synth_ai/sdk/graphs/__init__.py +15 -0
- synth_ai/sdk/graphs/completions.py +570 -0
- synth_ai/{inference → sdk/inference}/__init__.py +0 -1
- synth_ai/sdk/inference/client.py +128 -0
- synth_ai/sdk/jobs/__init__.py +16 -0
- synth_ai/sdk/jobs/client.py +371 -0
- synth_ai/sdk/judging/__init__.py +14 -0
- synth_ai/sdk/judging/base.py +24 -0
- synth_ai/sdk/judging/client.py +40 -0
- synth_ai/sdk/judging/schemas.py +222 -0
- synth_ai/sdk/judging/types.py +42 -0
- synth_ai/sdk/learning/__init__.py +99 -0
- synth_ai/sdk/learning/algorithms.py +14 -0
- synth_ai/{learning → sdk/learning}/client.py +121 -30
- synth_ai/sdk/learning/config.py +5 -0
- synth_ai/{learning → sdk/learning}/constants.py +0 -2
- synth_ai/sdk/learning/context_learning_client.py +531 -0
- synth_ai/sdk/learning/context_learning_types.py +292 -0
- synth_ai/sdk/learning/ft_client.py +7 -0
- synth_ai/{learning → sdk/learning}/health.py +15 -9
- synth_ai/{learning → sdk/learning}/jobs.py +44 -47
- synth_ai/sdk/learning/prompt_extraction.py +334 -0
- synth_ai/sdk/learning/prompt_learning_client.py +455 -0
- synth_ai/sdk/learning/prompt_learning_types.py +186 -0
- synth_ai/{rl → sdk/learning/rl}/__init__.py +13 -8
- synth_ai/{learning/rl_client.py → sdk/learning/rl/client.py} +89 -77
- synth_ai/sdk/learning/rl/config.py +31 -0
- synth_ai/{rl → sdk/learning/rl}/contracts.py +5 -14
- synth_ai/{rl → sdk/learning/rl}/env_keys.py +45 -16
- synth_ai/sdk/learning/rl/secrets.py +13 -0
- synth_ai/sdk/learning/rl_client.py +5 -0
- synth_ai/sdk/learning/sft/__init__.py +29 -0
- synth_ai/sdk/learning/sft/client.py +95 -0
- synth_ai/sdk/learning/sft/config.py +270 -0
- synth_ai/sdk/learning/sft/data.py +698 -0
- synth_ai/sdk/learning/sse.py +57 -0
- synth_ai/sdk/learning/validators.py +52 -0
- synth_ai/sdk/localapi/__init__.py +40 -0
- synth_ai/sdk/localapi/apps/__init__.py +28 -0
- synth_ai/sdk/localapi/client.py +10 -0
- synth_ai/sdk/localapi/contracts.py +10 -0
- synth_ai/sdk/localapi/helpers.py +519 -0
- synth_ai/sdk/localapi/rollouts.py +87 -0
- synth_ai/sdk/localapi/server.py +29 -0
- synth_ai/sdk/localapi/template.py +70 -0
- synth_ai/sdk/streaming/__init__.py +35 -0
- synth_ai/sdk/streaming/config.py +94 -0
- synth_ai/sdk/streaming/handlers.py +1997 -0
- synth_ai/sdk/streaming/streamer.py +713 -0
- synth_ai/sdk/streaming/types.py +112 -0
- synth_ai/sdk/task/__init__.py +164 -0
- synth_ai/sdk/task/apps/__init__.py +169 -0
- synth_ai/sdk/task/auth.py +165 -0
- synth_ai/sdk/task/client.py +175 -0
- synth_ai/sdk/task/config.py +257 -0
- synth_ai/sdk/task/contracts.py +219 -0
- synth_ai/sdk/task/datasets.py +108 -0
- synth_ai/sdk/task/errors.py +50 -0
- synth_ai/sdk/task/health.py +34 -0
- synth_ai/sdk/task/in_process.py +1190 -0
- synth_ai/sdk/task/in_process_runner.py +314 -0
- synth_ai/sdk/task/inference_api.py +299 -0
- synth_ai/sdk/task/json.py +111 -0
- synth_ai/sdk/task/proxy.py +287 -0
- synth_ai/sdk/task/rubrics/__init__.py +55 -0
- synth_ai/sdk/task/rubrics/loaders.py +156 -0
- synth_ai/sdk/task/rubrics/models.py +57 -0
- synth_ai/sdk/task/rubrics/scoring.py +116 -0
- synth_ai/sdk/task/rubrics/strict.py +149 -0
- synth_ai/sdk/task/rubrics.py +219 -0
- synth_ai/sdk/task/server.py +631 -0
- synth_ai/sdk/task/trace_correlation_helpers.py +539 -0
- synth_ai/sdk/task/tracing_utils.py +95 -0
- synth_ai/sdk/task/validators.py +441 -0
- synth_ai/sdk/task/vendors.py +59 -0
- synth_ai/sdk/training/__init__.py +102 -0
- synth_ai/sdk/tunnels/__init__.py +83 -0
- synth_ai/sdk/tunnels/cleanup.py +83 -0
- synth_ai/sdk/tunnels/ports.py +120 -0
- synth_ai/utils/__init__.py +213 -0
- synth_ai-0.4.3.dist-info/METADATA +262 -0
- synth_ai-0.4.3.dist-info/RECORD +370 -0
- {synth_ai-0.2.6.dev1.dist-info → synth_ai-0.4.3.dist-info}/entry_points.txt +0 -1
- synth_ai/cli/calc.py +0 -69
- synth_ai/cli/demo.py +0 -131
- synth_ai/cli/legacy_root_backup.py +0 -470
- synth_ai/cli/man.py +0 -106
- synth_ai/cli/rl_demo.py +0 -137
- synth_ai/cli/status.py +0 -133
- synth_ai/config/base_url.py +0 -98
- synth_ai/core/experiment.py +0 -15
- synth_ai/core/system.py +0 -15
- synth_ai/demos/core/__init__.py +0 -1
- synth_ai/demos/core/cli.py +0 -685
- synth_ai/demos/demo_task_apps/__init__.py +0 -1
- synth_ai/demos/demo_task_apps/math/config.toml +0 -44
- synth_ai/demos/demo_task_apps/math/deploy_task_app.sh +0 -22
- synth_ai/environments/__init__.py +0 -31
- synth_ai/environments/environment/__init__.py +0 -1
- synth_ai/environments/environment/artifacts/__init__.py +0 -1
- synth_ai/environments/environment/artifacts/base.py +0 -52
- synth_ai/environments/environment/core.py +0 -67
- synth_ai/environments/environment/db/__init__.py +0 -1
- synth_ai/environments/environment/db/sqlite.py +0 -45
- synth_ai/environments/environment/registry.py +0 -233
- synth_ai/environments/environment/resources/sqlite.py +0 -45
- synth_ai/environments/environment/results.py +0 -1
- synth_ai/environments/environment/rewards/__init__.py +0 -1
- synth_ai/environments/environment/rewards/core.py +0 -29
- synth_ai/environments/environment/shared_engine.py +0 -26
- synth_ai/environments/environment/tools/__init__.py +0 -200
- synth_ai/environments/examples/__init__.py +0 -1
- synth_ai/environments/examples/bandit/__init__.py +0 -33
- synth_ai/environments/examples/bandit/engine.py +0 -294
- synth_ai/environments/examples/bandit/environment.py +0 -194
- synth_ai/environments/examples/bandit/taskset.py +0 -200
- synth_ai/environments/examples/crafter_classic/__init__.py +0 -8
- synth_ai/environments/examples/crafter_classic/agent_demos/analyze_semantic_words_markdown.py +0 -250
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +0 -59
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +0 -152
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_config.toml +0 -24
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +0 -1194
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/crafter_synth_config.toml +0 -56
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_config_modal.toml +0 -32
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -724
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/kick_off_ft_modal.py +0 -384
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_action_results.py +0 -53
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_agent_actions.py +0 -178
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_latest_run.py +0 -222
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_lm_traces.py +0 -183
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_no_rewards.py +0 -210
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_trace_issue.py +0 -206
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_db_schema.py +0 -49
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_latest_results.py +0 -64
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/debug_agent_responses.py +0 -88
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/quick_trace_check.py +0 -77
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/compare_experiments.py +0 -324
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/kick_off_ft_oai.py +0 -362
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/multi_model_config.toml +0 -49
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_enhanced_hooks.py +0 -332
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_events.py +0 -97
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_results.py +0 -217
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_hook_storage.py +0 -87
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_seeds.py +0 -88
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/compare_seed_performance.py +0 -195
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/custom_eval_pipelines.py +0 -400
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/plot_hook_frequency.py +0 -195
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/seed_analysis_summary.py +0 -56
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/run_rollouts_for_models_and_compare_v3.py +0 -858
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +0 -52
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +0 -874
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +0 -1412
- synth_ai/environments/examples/crafter_classic/agent_demos/example_v3_usage.py +0 -216
- synth_ai/environments/examples/crafter_classic/agent_demos/old/compare_traces.py +0 -296
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_comprehensive_evaluation.py +0 -58
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_env_serialization.py +0 -464
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_evaluation_browser.py +0 -152
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_quick_evaluation.py +0 -51
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_trace_evaluation.py +0 -1412
- synth_ai/environments/examples/crafter_classic/agent_demos/old/debug_player_loss.py +0 -112
- synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_service.py +0 -203
- synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_slowness.py +0 -305
- synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_by_difficulty.py +0 -126
- synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_example.py +0 -94
- synth_ai/environments/examples/crafter_classic/agent_demos/old/explore_saved_states.py +0 -142
- synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft.py +0 -26
- synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft_OLD.py +0 -984
- synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_gemini.py +0 -724
- synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_modal.py +0 -386
- synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_metadata.py +0 -205
- synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_gemini.py +0 -150
- synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_modal.py +0 -283
- synth_ai/environments/examples/crafter_classic/agent_demos/old/prepare_vertex_ft.py +0 -280
- synth_ai/environments/examples/crafter_classic/agent_demos/old/profile_env_slowness.py +0 -456
- synth_ai/environments/examples/crafter_classic/agent_demos/old/replicate_issue.py +0 -166
- synth_ai/environments/examples/crafter_classic/agent_demos/old/run_and_eval.py +0 -102
- synth_ai/environments/examples/crafter_classic/agent_demos/old/run_comparison.py +0 -128
- synth_ai/environments/examples/crafter_classic/agent_demos/old/run_qwen_rollouts.py +0 -655
- synth_ai/environments/examples/crafter_classic/agent_demos/old/trace_eval_OLD.py +0 -202
- synth_ai/environments/examples/crafter_classic/agent_demos/old/validate_openai_format.py +0 -166
- synth_ai/environments/examples/crafter_classic/config_logging.py +0 -111
- synth_ai/environments/examples/crafter_classic/debug_translation.py +0 -0
- synth_ai/environments/examples/crafter_classic/engine.py +0 -579
- synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +0 -64
- synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +0 -6
- synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +0 -75
- synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +0 -267
- synth_ai/environments/examples/crafter_classic/environment.py +0 -404
- synth_ai/environments/examples/crafter_classic/taskset.py +0 -233
- synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +0 -228
- synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +0 -299
- synth_ai/environments/examples/crafter_custom/__init__.py +0 -4
- synth_ai/environments/examples/crafter_custom/agent_demos/__init__.py +0 -1
- synth_ai/environments/examples/crafter_custom/agent_demos/trace_eval.py +0 -202
- synth_ai/environments/examples/crafter_custom/crafter/__init__.py +0 -7
- synth_ai/environments/examples/crafter_custom/crafter/config.py +0 -182
- synth_ai/environments/examples/crafter_custom/crafter/constants.py +0 -8
- synth_ai/environments/examples/crafter_custom/crafter/engine.py +0 -269
- synth_ai/environments/examples/crafter_custom/crafter/env.py +0 -262
- synth_ai/environments/examples/crafter_custom/crafter/objects.py +0 -417
- synth_ai/environments/examples/crafter_custom/crafter/recorder.py +0 -187
- synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +0 -118
- synth_ai/environments/examples/crafter_custom/dataset_builder.py +0 -373
- synth_ai/environments/examples/crafter_custom/environment.py +0 -312
- synth_ai/environments/examples/crafter_custom/old/analyze_diamond_issue.py +0 -159
- synth_ai/environments/examples/crafter_custom/old/analyze_diamond_spawning.py +0 -158
- synth_ai/environments/examples/crafter_custom/old/compare_worlds.py +0 -71
- synth_ai/environments/examples/crafter_custom/old/dataset_stats.py +0 -105
- synth_ai/environments/examples/crafter_custom/old/diamond_spawning_summary.py +0 -119
- synth_ai/environments/examples/crafter_custom/old/example_dataset_usage.py +0 -52
- synth_ai/environments/examples/crafter_custom/run_dataset.py +0 -305
- synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +0 -156
- synth_ai/environments/examples/enron/art_helpers/local_email_db.py +0 -281
- synth_ai/environments/examples/enron/art_helpers/types_enron.py +0 -25
- synth_ai/environments/examples/enron/engine.py +0 -295
- synth_ai/environments/examples/enron/environment.py +0 -166
- synth_ai/environments/examples/enron/taskset.py +0 -112
- synth_ai/environments/examples/enron/units/keyword_stats.py +0 -112
- synth_ai/environments/examples/minigrid/__init__.py +0 -48
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +0 -1188
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +0 -48
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +0 -562
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +0 -221
- synth_ai/environments/examples/minigrid/engine.py +0 -589
- synth_ai/environments/examples/minigrid/environment.py +0 -274
- synth_ai/environments/examples/minigrid/environment_mapping.py +0 -242
- synth_ai/environments/examples/minigrid/puzzle_loader.py +0 -417
- synth_ai/environments/examples/minigrid/taskset.py +0 -583
- synth_ai/environments/examples/nethack/__init__.py +0 -7
- synth_ai/environments/examples/nethack/achievements.py +0 -337
- synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +0 -981
- synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +0 -74
- synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +0 -831
- synth_ai/environments/examples/nethack/engine.py +0 -739
- synth_ai/environments/examples/nethack/environment.py +0 -256
- synth_ai/environments/examples/nethack/helpers/__init__.py +0 -41
- synth_ai/environments/examples/nethack/helpers/action_mapping.py +0 -301
- synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +0 -402
- synth_ai/environments/examples/nethack/helpers/observation_utils.py +0 -433
- synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +0 -200
- synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +0 -269
- synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +0 -308
- synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +0 -431
- synth_ai/environments/examples/nethack/taskset.py +0 -323
- synth_ai/environments/examples/red/__init__.py +0 -7
- synth_ai/environments/examples/red/agent_demos/__init__.py +0 -1
- synth_ai/environments/examples/red/config_logging.py +0 -110
- synth_ai/environments/examples/red/engine.py +0 -694
- synth_ai/environments/examples/red/engine_helpers/__init__.py +0 -1
- synth_ai/environments/examples/red/engine_helpers/memory_map.py +0 -28
- synth_ai/environments/examples/red/engine_helpers/reward_components.py +0 -276
- synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +0 -142
- synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +0 -57
- synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +0 -284
- synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +0 -150
- synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +0 -138
- synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +0 -57
- synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +0 -331
- synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +0 -121
- synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +0 -559
- synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +0 -313
- synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +0 -148
- synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +0 -247
- synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +0 -368
- synth_ai/environments/examples/red/engine_helpers/state_extraction.py +0 -140
- synth_ai/environments/examples/red/environment.py +0 -238
- synth_ai/environments/examples/red/taskset.py +0 -79
- synth_ai/environments/examples/red/units/__init__.py +0 -1
- synth_ai/environments/examples/sokoban/__init__.py +0 -1
- synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +0 -899
- synth_ai/environments/examples/sokoban/engine.py +0 -678
- synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +0 -1
- synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +0 -657
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +0 -18
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +0 -3
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +0 -131
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +0 -370
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +0 -332
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +0 -306
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +0 -67
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +0 -115
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +0 -123
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +0 -394
- synth_ai/environments/examples/sokoban/environment.py +0 -229
- synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +0 -440
- synth_ai/environments/examples/sokoban/puzzle_loader.py +0 -312
- synth_ai/environments/examples/sokoban/taskset.py +0 -428
- synth_ai/environments/examples/sokoban/units/astar_common.py +0 -95
- synth_ai/environments/examples/tictactoe/__init__.py +0 -1
- synth_ai/environments/examples/tictactoe/engine.py +0 -368
- synth_ai/environments/examples/tictactoe/environment.py +0 -240
- synth_ai/environments/examples/tictactoe/taskset.py +0 -215
- synth_ai/environments/examples/verilog/__init__.py +0 -10
- synth_ai/environments/examples/verilog/engine.py +0 -329
- synth_ai/environments/examples/verilog/environment.py +0 -350
- synth_ai/environments/examples/verilog/taskset.py +0 -420
- synth_ai/environments/examples/wordle/__init__.py +0 -29
- synth_ai/environments/examples/wordle/engine.py +0 -398
- synth_ai/environments/examples/wordle/environment.py +0 -159
- synth_ai/environments/examples/wordle/helpers/generate_instances_wordfreq.py +0 -75
- synth_ai/environments/examples/wordle/taskset.py +0 -230
- synth_ai/environments/reproducibility/core.py +0 -42
- synth_ai/environments/reproducibility/helpers.py +0 -0
- synth_ai/environments/reproducibility/tree.py +0 -364
- synth_ai/environments/service/app.py +0 -91
- synth_ai/environments/service/core_routes.py +0 -1020
- synth_ai/environments/service/external_registry.py +0 -56
- synth_ai/environments/service/registry.py +0 -9
- synth_ai/environments/stateful/__init__.py +0 -1
- synth_ai/environments/stateful/core.py +0 -163
- synth_ai/environments/stateful/engine.py +0 -21
- synth_ai/environments/stateful/state.py +0 -7
- synth_ai/environments/tasks/api.py +0 -19
- synth_ai/environments/tasks/core.py +0 -80
- synth_ai/environments/tasks/filters.py +0 -41
- synth_ai/environments/tasks/utils.py +0 -91
- synth_ai/environments/v0_observability/history.py +0 -3
- synth_ai/environments/v0_observability/log.py +0 -2
- synth_ai/evals/base.py +0 -15
- synth_ai/experimental/synth_oss.py +0 -446
- synth_ai/http.py +0 -102
- synth_ai/inference/client.py +0 -20
- synth_ai/install_sqld.sh +0 -40
- synth_ai/jobs/client.py +0 -246
- synth_ai/learning/__init__.py +0 -24
- synth_ai/learning/config.py +0 -43
- synth_ai/learning/filtering.py +0 -0
- synth_ai/learning/ft_client.py +0 -59
- 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/learning/sse.py +0 -58
- synth_ai/learning/validators.py +0 -48
- synth_ai/lm/__init__.py +0 -51
- synth_ai/lm/caching/constants.py +0 -6
- synth_ai/lm/caching/dbs.py +0 -0
- synth_ai/lm/caching/ephemeral.py +0 -102
- synth_ai/lm/caching/handler.py +0 -137
- synth_ai/lm/caching/initialize.py +0 -11
- synth_ai/lm/caching/persistent.py +0 -114
- synth_ai/lm/config.py +0 -110
- synth_ai/lm/constants.py +0 -32
- synth_ai/lm/core/__init__.py +0 -8
- synth_ai/lm/core/all.py +0 -73
- synth_ai/lm/core/exceptions.py +0 -7
- synth_ai/lm/core/main.py +0 -319
- synth_ai/lm/core/main_v3.py +0 -594
- synth_ai/lm/core/synth_models.py +0 -48
- synth_ai/lm/core/vendor_clients.py +0 -188
- synth_ai/lm/cost/__init__.py +0 -0
- synth_ai/lm/cost/monitor.py +0 -1
- synth_ai/lm/cost/statefulness.py +0 -1
- synth_ai/lm/injection.py +0 -80
- synth_ai/lm/overrides.py +0 -206
- synth_ai/lm/provider_support/__init__.py +0 -8
- synth_ai/lm/provider_support/anthropic.py +0 -972
- synth_ai/lm/provider_support/openai.py +0 -1139
- synth_ai/lm/provider_support/suppress_logging.py +0 -31
- synth_ai/lm/structured_outputs/__init__.py +0 -0
- synth_ai/lm/structured_outputs/handler.py +0 -440
- synth_ai/lm/structured_outputs/inject.py +0 -297
- synth_ai/lm/structured_outputs/rehabilitate.py +0 -185
- synth_ai/lm/tools/__init__.py +0 -3
- synth_ai/lm/tools/base.py +0 -172
- synth_ai/lm/unified_interface.py +0 -202
- synth_ai/lm/vendors/__init__.py +0 -0
- synth_ai/lm/vendors/base.py +0 -81
- synth_ai/lm/vendors/core/__init__.py +0 -0
- synth_ai/lm/vendors/core/anthropic_api.py +0 -387
- synth_ai/lm/vendors/core/gemini_api.py +0 -292
- synth_ai/lm/vendors/core/mistral_api.py +0 -322
- synth_ai/lm/vendors/core/openai_api.py +0 -220
- synth_ai/lm/vendors/core/synth_dev_api.py +0 -0
- synth_ai/lm/vendors/local/__init__.py +0 -0
- synth_ai/lm/vendors/local/ollama.py +0 -0
- synth_ai/lm/vendors/openai_standard.py +0 -780
- synth_ai/lm/vendors/openai_standard_responses.py +0 -256
- synth_ai/lm/vendors/retries.py +0 -22
- synth_ai/lm/vendors/supported/__init__.py +0 -0
- synth_ai/lm/vendors/supported/custom_endpoint.py +0 -417
- synth_ai/lm/vendors/supported/deepseek.py +0 -69
- synth_ai/lm/vendors/supported/grok.py +0 -75
- synth_ai/lm/vendors/supported/groq.py +0 -16
- synth_ai/lm/vendors/supported/ollama.py +0 -15
- synth_ai/lm/vendors/supported/openrouter.py +0 -74
- synth_ai/lm/vendors/supported/together.py +0 -11
- synth_ai/lm/vendors/synth_client.py +0 -808
- synth_ai/lm/warmup.py +0 -186
- synth_ai/rl/secrets.py +0 -19
- synth_ai/scripts/verify_rewards.py +0 -100
- synth_ai/task/__init__.py +0 -10
- synth_ai/task/contracts.py +0 -120
- synth_ai/task/health.py +0 -28
- synth_ai/task/validators.py +0 -12
- synth_ai/tracing/__init__.py +0 -30
- synth_ai/tracing_v1/__init__.py +0 -33
- synth_ai/tracing_v3/config.py +0 -84
- synth_ai/tracing_v3/storage/config.py +0 -62
- synth_ai/tracing_v3/turso/__init__.py +0 -25
- synth_ai/tracing_v3/turso/daemon.py +0 -144
- synth_ai/tracing_v3/turso/manager.py +0 -760
- synth_ai/v0/tracing/__init__.py +0 -0
- synth_ai/v0/tracing/abstractions.py +0 -224
- synth_ai/v0/tracing/base_client.py +0 -91
- synth_ai/v0/tracing/client_manager.py +0 -131
- synth_ai/v0/tracing/config.py +0 -140
- synth_ai/v0/tracing/context.py +0 -146
- synth_ai/v0/tracing/decorators.py +0 -680
- synth_ai/v0/tracing/events/__init__.py +0 -0
- synth_ai/v0/tracing/events/manage.py +0 -147
- synth_ai/v0/tracing/events/scope.py +0 -86
- synth_ai/v0/tracing/events/store.py +0 -228
- synth_ai/v0/tracing/immediate_client.py +0 -151
- synth_ai/v0/tracing/local.py +0 -18
- synth_ai/v0/tracing/log_client_base.py +0 -73
- synth_ai/v0/tracing/retry_queue.py +0 -186
- synth_ai/v0/tracing/trackers.py +0 -515
- synth_ai/v0/tracing/upload.py +0 -510
- synth_ai/v0/tracing/utils.py +0 -9
- synth_ai/v0/tracing_v1/__init__.py +0 -16
- synth_ai/v0/tracing_v1/abstractions.py +0 -224
- synth_ai/v0/tracing_v1/base_client.py +0 -91
- synth_ai/v0/tracing_v1/client_manager.py +0 -131
- synth_ai/v0/tracing_v1/config.py +0 -140
- synth_ai/v0/tracing_v1/context.py +0 -146
- synth_ai/v0/tracing_v1/decorators.py +0 -701
- synth_ai/v0/tracing_v1/events/__init__.py +0 -0
- synth_ai/v0/tracing_v1/events/manage.py +0 -147
- synth_ai/v0/tracing_v1/events/scope.py +0 -86
- synth_ai/v0/tracing_v1/events/store.py +0 -228
- synth_ai/v0/tracing_v1/immediate_client.py +0 -151
- synth_ai/v0/tracing_v1/local.py +0 -18
- synth_ai/v0/tracing_v1/log_client_base.py +0 -73
- synth_ai/v0/tracing_v1/retry_queue.py +0 -186
- synth_ai/v0/tracing_v1/trackers.py +0 -515
- synth_ai/v0/tracing_v1/upload.py +0 -525
- synth_ai/v0/tracing_v1/utils.py +0 -9
- synth_ai/zyk/__init__.py +0 -30
- synth_ai-0.2.6.dev1.dist-info/METADATA +0 -106
- synth_ai-0.2.6.dev1.dist-info/RECORD +0 -416
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/__init__.py +0 -0
- /synth_ai/{lm/caching → core/apps}/__init__.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/lm_call_record_abstractions.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/storage/__init__.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/storage/exceptions.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/storage/types.py +0 -0
- /synth_ai/{compound/cais.py → py.typed} +0 -0
- /synth_ai/{learning → sdk/learning}/core.py +0 -0
- /synth_ai/{learning → sdk/learning}/gateway.py +0 -0
- {synth_ai-0.2.6.dev1.dist-info → synth_ai-0.4.3.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.6.dev1.dist-info → synth_ai-0.4.3.dist-info}/licenses/LICENSE +0 -0
- {synth_ai-0.2.6.dev1.dist-info → synth_ai-0.4.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
"""FastAPI scaffolding for Task Apps (local dev + deployment).
|
|
2
|
+
|
|
3
|
+
Prefer synth_ai.sdk.localapi.server moving forward. This module remains for
|
|
4
|
+
backward compatibility during the naming transition.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import inspect
|
|
11
|
+
import os
|
|
12
|
+
import threading
|
|
13
|
+
from collections.abc import Awaitable, Callable, Iterable, Mapping, MutableMapping, Sequence
|
|
14
|
+
from contextlib import asynccontextmanager
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
import httpx
|
|
20
|
+
from fastapi import APIRouter, Depends, FastAPI, Query, Request
|
|
21
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
22
|
+
from starlette.middleware import Middleware
|
|
23
|
+
|
|
24
|
+
from synth_ai.core.telemetry import log_info
|
|
25
|
+
|
|
26
|
+
from .auth import normalize_environment_api_key, require_api_key_dependency
|
|
27
|
+
from .contracts import RolloutRequest, RolloutResponse, TaskInfo
|
|
28
|
+
from .datasets import TaskDatasetRegistry
|
|
29
|
+
from .errors import http_exception
|
|
30
|
+
from .json import to_jsonable
|
|
31
|
+
from .proxy import (
|
|
32
|
+
inject_system_hint,
|
|
33
|
+
prepare_for_groq,
|
|
34
|
+
prepare_for_openai,
|
|
35
|
+
synthesize_tool_call_if_missing,
|
|
36
|
+
)
|
|
37
|
+
from .rubrics import Rubric
|
|
38
|
+
from .vendors import get_groq_key_or_503, get_openai_key_or_503, normalize_vendor_keys
|
|
39
|
+
|
|
40
|
+
TasksetDescriptor = Callable[[], Mapping[str, Any] | Awaitable[Mapping[str, Any]]]
|
|
41
|
+
InstanceProvider = Callable[[Sequence[int]], Iterable[TaskInfo] | Awaitable[Iterable[TaskInfo]]]
|
|
42
|
+
RolloutExecutor = Callable[[RolloutRequest, Request], Any | Awaitable[Any]]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _default_app_state() -> dict[str, Any]:
|
|
46
|
+
return {}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(slots=True)
|
|
50
|
+
class RubricBundle:
|
|
51
|
+
"""Optional rubrics advertised by the task app."""
|
|
52
|
+
|
|
53
|
+
outcome: Rubric | None = None
|
|
54
|
+
events: Rubric | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(slots=True)
|
|
58
|
+
class ProxyConfig:
|
|
59
|
+
"""Configuration for optional vendor proxy endpoints."""
|
|
60
|
+
|
|
61
|
+
enable_openai: bool = False
|
|
62
|
+
enable_groq: bool = False
|
|
63
|
+
system_hint: str | None = None
|
|
64
|
+
openai_url: str = "https://api.openai.com/v1/chat/completions"
|
|
65
|
+
groq_url: str = "https://api.groq.com/openai/v1/chat/completions"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(slots=True)
|
|
69
|
+
class TaskAppConfig:
|
|
70
|
+
"""Declarative configuration describing a Task App.
|
|
71
|
+
|
|
72
|
+
A TaskAppConfig defines all the components needed to create a task app:
|
|
73
|
+
- Task information (base_task_info)
|
|
74
|
+
- Task set description (describe_taskset)
|
|
75
|
+
- Task instance provider (provide_task_instances)
|
|
76
|
+
- Rollout executor (rollout)
|
|
77
|
+
- Optional rubrics, datasets, proxy config, etc.
|
|
78
|
+
|
|
79
|
+
This config is used by `create_task_app()` to build a FastAPI application
|
|
80
|
+
that implements the Synth AI task app contract.
|
|
81
|
+
|
|
82
|
+
Example:
|
|
83
|
+
>>> from synth_ai.sdk.task.server import TaskAppConfig, create_task_app
|
|
84
|
+
>>> from synth_ai.sdk.task.contracts import TaskInfo
|
|
85
|
+
>>>
|
|
86
|
+
>>> def build_config() -> TaskAppConfig:
|
|
87
|
+
... return TaskAppConfig(
|
|
88
|
+
... app_id="my_task",
|
|
89
|
+
... name="My Task App",
|
|
90
|
+
... description="A simple task app",
|
|
91
|
+
... base_task_info=TaskInfo(...),
|
|
92
|
+
... describe_taskset=lambda: {"splits": ["train", "val"]},
|
|
93
|
+
... provide_task_instances=lambda seeds: [...],
|
|
94
|
+
... rollout=lambda req, r: {...},
|
|
95
|
+
... )
|
|
96
|
+
>>>
|
|
97
|
+
>>> app = create_task_app(build_config())
|
|
98
|
+
>>> # app is a FastAPI instance ready to run
|
|
99
|
+
|
|
100
|
+
Attributes:
|
|
101
|
+
app_id: Unique identifier for this task app
|
|
102
|
+
name: Human-readable name
|
|
103
|
+
description: Description of what this task app does
|
|
104
|
+
base_task_info: Base TaskInfo that all instances inherit from
|
|
105
|
+
describe_taskset: Function that returns taskset metadata
|
|
106
|
+
provide_task_instances: Function that yields TaskInfo instances for given seeds
|
|
107
|
+
rollout: Function that executes a rollout request and returns response
|
|
108
|
+
dataset_registry: Optional registry for task datasets
|
|
109
|
+
rubrics: Optional rubrics for evaluation
|
|
110
|
+
proxy: Optional proxy config for vendor endpoints
|
|
111
|
+
routers: Additional FastAPI routers to include
|
|
112
|
+
middleware: Additional middleware to apply
|
|
113
|
+
app_state: Mutable state dict accessible to routes
|
|
114
|
+
require_api_key: Whether to require API key authentication
|
|
115
|
+
expose_debug_env: Whether to expose debug environment endpoint
|
|
116
|
+
cors_origins: CORS allowed origins
|
|
117
|
+
startup_hooks: Functions to call on app startup
|
|
118
|
+
shutdown_hooks: Functions to call on app shutdown
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
app_id: str
|
|
122
|
+
name: str
|
|
123
|
+
description: str
|
|
124
|
+
base_task_info: TaskInfo
|
|
125
|
+
describe_taskset: TasksetDescriptor
|
|
126
|
+
provide_task_instances: InstanceProvider
|
|
127
|
+
rollout: RolloutExecutor
|
|
128
|
+
dataset_registry: TaskDatasetRegistry | None = None
|
|
129
|
+
rubrics: RubricBundle | None = field(default_factory=RubricBundle)
|
|
130
|
+
proxy: ProxyConfig | None = None
|
|
131
|
+
routers: Sequence[APIRouter] = field(default_factory=tuple)
|
|
132
|
+
middleware: Sequence[Middleware] = field(default_factory=tuple)
|
|
133
|
+
app_state: MutableMapping[str, Any] = field(default_factory=_default_app_state)
|
|
134
|
+
require_api_key: bool = True
|
|
135
|
+
expose_debug_env: bool = True
|
|
136
|
+
cors_origins: Sequence[str] | None = None
|
|
137
|
+
startup_hooks: Sequence[Callable[[], None | Awaitable[None]]] = field(default_factory=tuple)
|
|
138
|
+
shutdown_hooks: Sequence[Callable[[], None | Awaitable[None]]] = field(default_factory=tuple)
|
|
139
|
+
|
|
140
|
+
def clone(self) -> TaskAppConfig:
|
|
141
|
+
"""Return a shallow copy safe to mutate when wiring the app."""
|
|
142
|
+
|
|
143
|
+
return TaskAppConfig(
|
|
144
|
+
app_id=self.app_id,
|
|
145
|
+
name=self.name,
|
|
146
|
+
description=self.description,
|
|
147
|
+
base_task_info=self.base_task_info,
|
|
148
|
+
describe_taskset=self.describe_taskset,
|
|
149
|
+
provide_task_instances=self.provide_task_instances,
|
|
150
|
+
rollout=self.rollout,
|
|
151
|
+
dataset_registry=self.dataset_registry,
|
|
152
|
+
rubrics=self.rubrics or RubricBundle(),
|
|
153
|
+
proxy=self.proxy,
|
|
154
|
+
routers=tuple(self.routers),
|
|
155
|
+
middleware=tuple(self.middleware),
|
|
156
|
+
app_state=dict(self.app_state),
|
|
157
|
+
require_api_key=self.require_api_key,
|
|
158
|
+
expose_debug_env=self.expose_debug_env,
|
|
159
|
+
cors_origins=tuple(self.cors_origins or ()),
|
|
160
|
+
startup_hooks=tuple(self.startup_hooks),
|
|
161
|
+
shutdown_hooks=tuple(self.shutdown_hooks),
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class LocalAPIConfig(TaskAppConfig):
|
|
166
|
+
"""Alias for TaskAppConfig with LocalAPI naming."""
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _maybe_await(result: Any) -> Awaitable[Any]:
|
|
170
|
+
if inspect.isawaitable(result):
|
|
171
|
+
return asyncio.ensure_future(result)
|
|
172
|
+
loop = asyncio.get_event_loop()
|
|
173
|
+
future: asyncio.Future[Any] = loop.create_future()
|
|
174
|
+
future.set_result(result)
|
|
175
|
+
return future
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _ensure_task_info(obj: Any) -> TaskInfo:
|
|
179
|
+
if isinstance(obj, TaskInfo):
|
|
180
|
+
return obj
|
|
181
|
+
if isinstance(obj, MutableMapping):
|
|
182
|
+
return TaskInfo.model_validate(obj)
|
|
183
|
+
raise TypeError(
|
|
184
|
+
f"Task instance provider must yield TaskInfo-compatible objects (got {type(obj)!r})"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _normalise_seeds(values: Sequence[int]) -> list[int]:
|
|
189
|
+
seeds: list[int] = []
|
|
190
|
+
for value in values:
|
|
191
|
+
try:
|
|
192
|
+
seeds.append(int(value))
|
|
193
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
194
|
+
raise ValueError(f"Seed values must be convertible to int (got {value!r})") from exc
|
|
195
|
+
return seeds
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _build_proxy_routes(
|
|
199
|
+
app: FastAPI, config: TaskAppConfig, auth_dependency: Callable[[Request], None]
|
|
200
|
+
) -> None:
|
|
201
|
+
proxy = config.proxy
|
|
202
|
+
if not proxy:
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
async def _call_vendor(
|
|
206
|
+
url: str, payload: dict[str, Any], headers: dict[str, str]
|
|
207
|
+
) -> dict[str, Any]:
|
|
208
|
+
async with httpx.AsyncClient(timeout=httpx.Timeout(600.0), follow_redirects=True) as client:
|
|
209
|
+
response = await client.post(url, json=payload, headers=headers)
|
|
210
|
+
data = (
|
|
211
|
+
response.json()
|
|
212
|
+
if response.headers.get("content-type", "").startswith("application/json")
|
|
213
|
+
else {"raw": response.text}
|
|
214
|
+
)
|
|
215
|
+
if response.status_code >= 400:
|
|
216
|
+
code = "vendor_error"
|
|
217
|
+
if url.startswith("https://api.openai.com"):
|
|
218
|
+
code = "openai_error"
|
|
219
|
+
elif "groq" in url:
|
|
220
|
+
code = "groq_error"
|
|
221
|
+
raise http_exception(
|
|
222
|
+
response.status_code,
|
|
223
|
+
code,
|
|
224
|
+
"Vendor proxy error",
|
|
225
|
+
extra={"status": response.status_code, "body": data},
|
|
226
|
+
)
|
|
227
|
+
return data
|
|
228
|
+
|
|
229
|
+
def _log_proxy(route: str, payload: dict[str, Any]) -> None:
|
|
230
|
+
try:
|
|
231
|
+
messages = payload.get("messages") if isinstance(payload, dict) else None
|
|
232
|
+
msg_count = len(messages) if isinstance(messages, list) else 0
|
|
233
|
+
tool_count = len(payload.get("tools") or []) if isinstance(payload, dict) else 0
|
|
234
|
+
model = payload.get("model") if isinstance(payload, dict) else None
|
|
235
|
+
print(
|
|
236
|
+
f"[task:proxy:{route}] model={model} messages={msg_count} tools={tool_count}",
|
|
237
|
+
flush=True,
|
|
238
|
+
)
|
|
239
|
+
except Exception: # pragma: no cover - best effort logging
|
|
240
|
+
pass
|
|
241
|
+
|
|
242
|
+
system_hint = proxy.system_hint
|
|
243
|
+
|
|
244
|
+
if proxy.enable_openai:
|
|
245
|
+
|
|
246
|
+
@app.post("/proxy/v1/chat/completions", dependencies=[Depends(auth_dependency)])
|
|
247
|
+
async def proxy_openai(body: dict[str, Any], request: Request) -> Any: # type: ignore[no-redef]
|
|
248
|
+
key = get_openai_key_or_503()
|
|
249
|
+
model = body.get("model") if isinstance(body.get("model"), str) else None
|
|
250
|
+
payload = prepare_for_openai(model, body)
|
|
251
|
+
payload = inject_system_hint(payload, system_hint or "")
|
|
252
|
+
_log_proxy("openai", payload)
|
|
253
|
+
data = await _call_vendor(proxy.openai_url, payload, {"Authorization": f"Bearer {key}"})
|
|
254
|
+
sanitized = synthesize_tool_call_if_missing(data)
|
|
255
|
+
return to_jsonable(sanitized)
|
|
256
|
+
|
|
257
|
+
if proxy.enable_groq:
|
|
258
|
+
|
|
259
|
+
@app.post("/proxy/groq/v1/chat/completions", dependencies=[Depends(auth_dependency)])
|
|
260
|
+
async def proxy_groq(body: dict[str, Any], request: Request) -> Any: # type: ignore[no-redef]
|
|
261
|
+
key = get_groq_key_or_503()
|
|
262
|
+
model = body.get("model") if isinstance(body.get("model"), str) else None
|
|
263
|
+
payload = prepare_for_groq(model, body)
|
|
264
|
+
payload = inject_system_hint(payload, system_hint or "")
|
|
265
|
+
_log_proxy("groq", payload)
|
|
266
|
+
data = await _call_vendor(
|
|
267
|
+
proxy.groq_url.rstrip("/"), payload, {"Authorization": f"Bearer {key}"}
|
|
268
|
+
)
|
|
269
|
+
sanitized = synthesize_tool_call_if_missing(data)
|
|
270
|
+
return to_jsonable(sanitized)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _auth_dependency_factory(config: TaskAppConfig) -> Callable[[Request], None]:
|
|
274
|
+
def _dependency(request: Request) -> None:
|
|
275
|
+
if not config.require_api_key:
|
|
276
|
+
return
|
|
277
|
+
require_api_key_dependency(request)
|
|
278
|
+
|
|
279
|
+
return _dependency
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def create_task_app(config: TaskAppConfig) -> FastAPI:
|
|
283
|
+
"""Create a FastAPI application from a TaskAppConfig.
|
|
284
|
+
|
|
285
|
+
This function builds a complete FastAPI application that implements the Synth AI
|
|
286
|
+
task app contract. The resulting app includes:
|
|
287
|
+
- Health check endpoints (/health, /)
|
|
288
|
+
- Task info endpoint (/task_info)
|
|
289
|
+
- Rollout endpoint (/rollout)
|
|
290
|
+
- Optional proxy endpoints for OpenAI/Groq
|
|
291
|
+
- Optional dataset registry endpoints
|
|
292
|
+
- CORS middleware (if configured)
|
|
293
|
+
- Authentication middleware (if require_api_key=True)
|
|
294
|
+
|
|
295
|
+
The app is ready to run with uvicorn or deploy to any ASGI-compatible server.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
config: TaskAppConfig describing the task app
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
FastAPI application instance ready to run
|
|
302
|
+
|
|
303
|
+
Example:
|
|
304
|
+
>>> from synth_ai.sdk.task.server import TaskAppConfig, create_task_app
|
|
305
|
+
>>>
|
|
306
|
+
>>> def build_config() -> TaskAppConfig:
|
|
307
|
+
... return TaskAppConfig(
|
|
308
|
+
... app_id="my_task",
|
|
309
|
+
... name="My Task",
|
|
310
|
+
... description="A task app",
|
|
311
|
+
... base_task_info=TaskInfo(...),
|
|
312
|
+
... describe_taskset=lambda: {"splits": ["train"]},
|
|
313
|
+
... provide_task_instances=lambda seeds: [...],
|
|
314
|
+
... rollout=lambda req, r: {...},
|
|
315
|
+
... )
|
|
316
|
+
>>>
|
|
317
|
+
>>> app = create_task_app(build_config())
|
|
318
|
+
>>> # Run with: uvicorn.run(app, host="0.0.0.0", port=8001)
|
|
319
|
+
"""
|
|
320
|
+
ctx: dict[str, Any] = {"app_id": config.app_id, "name": config.name}
|
|
321
|
+
log_info("create_task_app invoked", ctx=ctx)
|
|
322
|
+
cfg = config.clone()
|
|
323
|
+
cfg.rubrics = cfg.rubrics or RubricBundle()
|
|
324
|
+
app = FastAPI(title=cfg.name, description=cfg.description)
|
|
325
|
+
|
|
326
|
+
for key, value in cfg.app_state.items():
|
|
327
|
+
setattr(app.state, key, value)
|
|
328
|
+
|
|
329
|
+
if cfg.cors_origins is not None:
|
|
330
|
+
app.add_middleware(
|
|
331
|
+
CORSMiddleware, # type: ignore[arg-type]
|
|
332
|
+
allow_origins=list(cfg.cors_origins) or ["*"],
|
|
333
|
+
allow_credentials=True,
|
|
334
|
+
allow_methods=["*"],
|
|
335
|
+
allow_headers=["*"],
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
# Note: additional middleware from cfg.middleware is currently disabled to avoid typing ambiguity.
|
|
339
|
+
# for middleware in cfg.middleware:
|
|
340
|
+
# try:
|
|
341
|
+
# opts = getattr(middleware, "options", {})
|
|
342
|
+
# except Exception:
|
|
343
|
+
# opts = {}
|
|
344
|
+
# app.add_middleware(middleware.cls, **(opts if isinstance(opts, dict) else {}))
|
|
345
|
+
|
|
346
|
+
for router in cfg.routers:
|
|
347
|
+
try:
|
|
348
|
+
app.include_router(router)
|
|
349
|
+
except Exception:
|
|
350
|
+
try:
|
|
351
|
+
inner = getattr(router, "router", None)
|
|
352
|
+
if inner is not None:
|
|
353
|
+
app.include_router(inner)
|
|
354
|
+
except Exception:
|
|
355
|
+
raise
|
|
356
|
+
|
|
357
|
+
auth_dependency = _auth_dependency_factory(cfg)
|
|
358
|
+
|
|
359
|
+
def _call_hook(hook: Callable[..., Any]) -> Awaitable[Any]:
|
|
360
|
+
try:
|
|
361
|
+
params = inspect.signature(hook).parameters # type: ignore[arg-type]
|
|
362
|
+
except (TypeError, ValueError):
|
|
363
|
+
params = {}
|
|
364
|
+
if params:
|
|
365
|
+
return _maybe_await(hook(app)) # type: ignore[misc]
|
|
366
|
+
return _maybe_await(hook())
|
|
367
|
+
|
|
368
|
+
@asynccontextmanager
|
|
369
|
+
async def lifespan(_: FastAPI):
|
|
370
|
+
normalize_environment_api_key()
|
|
371
|
+
normalize_vendor_keys()
|
|
372
|
+
for hook in cfg.startup_hooks:
|
|
373
|
+
await _call_hook(hook)
|
|
374
|
+
try:
|
|
375
|
+
yield
|
|
376
|
+
finally:
|
|
377
|
+
for hook in cfg.shutdown_hooks:
|
|
378
|
+
await _call_hook(hook)
|
|
379
|
+
|
|
380
|
+
app.router.lifespan_context = lifespan
|
|
381
|
+
|
|
382
|
+
@app.get("/")
|
|
383
|
+
async def root() -> Mapping[str, Any]:
|
|
384
|
+
return to_jsonable({"status": "ok", "service": cfg.app_id})
|
|
385
|
+
|
|
386
|
+
@app.head("/")
|
|
387
|
+
async def root_head() -> Mapping[str, Any]:
|
|
388
|
+
return to_jsonable({"status": "ok"})
|
|
389
|
+
|
|
390
|
+
@app.get("/health", dependencies=[Depends(auth_dependency)])
|
|
391
|
+
async def health(request: Request) -> Mapping[str, Any]:
|
|
392
|
+
# If we got here, auth_dependency already verified the key exactly matches
|
|
393
|
+
expected = normalize_environment_api_key()
|
|
394
|
+
return to_jsonable(
|
|
395
|
+
{
|
|
396
|
+
"healthy": True,
|
|
397
|
+
"auth": {
|
|
398
|
+
"required": True,
|
|
399
|
+
"expected_prefix": (expected[:6] + "...") if expected else "<unset>",
|
|
400
|
+
},
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
@app.post("/done", dependencies=[Depends(auth_dependency)])
|
|
405
|
+
async def done() -> Mapping[str, Any]:
|
|
406
|
+
# Coordination endpoint for tests and automation; indicates app is reachable
|
|
407
|
+
return to_jsonable({"ok": True, "service": cfg.app_id})
|
|
408
|
+
|
|
409
|
+
@app.get("/info", dependencies=[Depends(auth_dependency)])
|
|
410
|
+
async def info() -> Mapping[str, Any]:
|
|
411
|
+
dataset_meta = cfg.base_task_info.dataset
|
|
412
|
+
rubrics: dict[str, Any] | None = None
|
|
413
|
+
rubric_bundle = cfg.rubrics
|
|
414
|
+
if rubric_bundle and (rubric_bundle.outcome or rubric_bundle.events):
|
|
415
|
+
rubrics = {
|
|
416
|
+
"outcome": rubric_bundle.outcome.model_dump() if rubric_bundle.outcome else None,
|
|
417
|
+
"events": rubric_bundle.events.model_dump() if rubric_bundle.events else None,
|
|
418
|
+
}
|
|
419
|
+
payload = {
|
|
420
|
+
"service": {
|
|
421
|
+
"task": cfg.base_task_info.task,
|
|
422
|
+
"version": cfg.base_task_info.task.version,
|
|
423
|
+
},
|
|
424
|
+
"dataset": dataset_meta,
|
|
425
|
+
"rubrics": rubrics,
|
|
426
|
+
"inference": cfg.base_task_info.inference,
|
|
427
|
+
"limits": cfg.base_task_info.limits,
|
|
428
|
+
}
|
|
429
|
+
return to_jsonable(payload)
|
|
430
|
+
|
|
431
|
+
@app.get("/task_info", dependencies=[Depends(auth_dependency)])
|
|
432
|
+
async def task_info(
|
|
433
|
+
seed: Sequence[int] | None = Query(default=None),
|
|
434
|
+
seeds: Sequence[int] | None = Query(default=None),
|
|
435
|
+
) -> Any:
|
|
436
|
+
all_seeds: list[int] = []
|
|
437
|
+
if seed:
|
|
438
|
+
all_seeds.extend(_normalise_seeds(seed))
|
|
439
|
+
if seeds:
|
|
440
|
+
all_seeds.extend(_normalise_seeds(seeds))
|
|
441
|
+
|
|
442
|
+
if not all_seeds:
|
|
443
|
+
descriptor_result = await _maybe_await(cfg.describe_taskset())
|
|
444
|
+
return to_jsonable({"taskset": descriptor_result})
|
|
445
|
+
|
|
446
|
+
instances = await _maybe_await(cfg.provide_task_instances(all_seeds))
|
|
447
|
+
payload = [to_jsonable(_ensure_task_info(instance).model_dump()) for instance in instances]
|
|
448
|
+
return payload[0] if len(payload) == 1 else payload
|
|
449
|
+
|
|
450
|
+
@app.post("/rollout", dependencies=[Depends(auth_dependency)])
|
|
451
|
+
async def rollout_endpoint(rollout_request: RolloutRequest, request: Request) -> Any:
|
|
452
|
+
result = await _maybe_await(cfg.rollout(rollout_request, request))
|
|
453
|
+
if isinstance(result, RolloutResponse):
|
|
454
|
+
return to_jsonable(result.model_dump())
|
|
455
|
+
if isinstance(result, Mapping):
|
|
456
|
+
try:
|
|
457
|
+
validated = RolloutResponse.model_validate(result)
|
|
458
|
+
except Exception:
|
|
459
|
+
return to_jsonable(result)
|
|
460
|
+
return to_jsonable(validated.model_dump())
|
|
461
|
+
raise TypeError("Rollout executor must return RolloutResponse or mapping")
|
|
462
|
+
|
|
463
|
+
if cfg.expose_debug_env:
|
|
464
|
+
|
|
465
|
+
@app.get("/debug/env", dependencies=[Depends(auth_dependency)])
|
|
466
|
+
async def debug_env() -> Mapping[str, Any]:
|
|
467
|
+
def _mask(value: str | None) -> str:
|
|
468
|
+
if not value:
|
|
469
|
+
return ""
|
|
470
|
+
return f"{value[:6]}…" if len(value) > 6 else value
|
|
471
|
+
|
|
472
|
+
return to_jsonable(
|
|
473
|
+
{
|
|
474
|
+
"has_ENVIRONMENT_API_KEY": bool(os.getenv("ENVIRONMENT_API_KEY")),
|
|
475
|
+
"OPENAI_API_KEY_prefix": _mask(os.getenv("OPENAI_API_KEY")),
|
|
476
|
+
"GROQ_API_KEY_prefix": _mask(os.getenv("GROQ_API_KEY")),
|
|
477
|
+
}
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
_build_proxy_routes(app, cfg, auth_dependency)
|
|
481
|
+
|
|
482
|
+
return app
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def _load_env_files(env_files: Sequence[str]) -> list[str]:
|
|
486
|
+
loaded: list[str] = []
|
|
487
|
+
if not env_files:
|
|
488
|
+
return loaded
|
|
489
|
+
try:
|
|
490
|
+
import dotenv
|
|
491
|
+
except Exception: # pragma: no cover - optional dep
|
|
492
|
+
return loaded
|
|
493
|
+
for path_str in env_files:
|
|
494
|
+
path = Path(path_str)
|
|
495
|
+
if not path.is_file():
|
|
496
|
+
continue
|
|
497
|
+
dotenv.load_dotenv(path, override=False)
|
|
498
|
+
loaded.append(str(path))
|
|
499
|
+
return loaded
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def run_task_app(
|
|
503
|
+
config_factory: Callable[[], TaskAppConfig],
|
|
504
|
+
*,
|
|
505
|
+
host: str = "0.0.0.0",
|
|
506
|
+
port: int = 8001,
|
|
507
|
+
reload: bool = False,
|
|
508
|
+
env_files: Sequence[str] = (),
|
|
509
|
+
) -> None:
|
|
510
|
+
"""Run a task app locally with uvicorn.
|
|
511
|
+
|
|
512
|
+
This is a convenience function that creates a task app from a config factory
|
|
513
|
+
and runs it with uvicorn. It handles environment file loading and service
|
|
514
|
+
registration for tunnel management.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
config_factory: Function that returns a TaskAppConfig
|
|
518
|
+
host: Host to bind to (default: "0.0.0.0")
|
|
519
|
+
port: Port to listen on (default: 8001)
|
|
520
|
+
reload: Enable auto-reload on file changes (default: False)
|
|
521
|
+
env_files: Paths to .env files to load (default: empty)
|
|
522
|
+
|
|
523
|
+
Example:
|
|
524
|
+
>>> from synth_ai.sdk.task.server import run_task_app
|
|
525
|
+
>>> from my_task_app import build_config
|
|
526
|
+
>>>
|
|
527
|
+
>>> run_task_app(
|
|
528
|
+
... build_config,
|
|
529
|
+
... host="127.0.0.1",
|
|
530
|
+
... port=8114,
|
|
531
|
+
... reload=True,
|
|
532
|
+
... env_files=[".env.local"],
|
|
533
|
+
... )
|
|
534
|
+
|
|
535
|
+
Raises:
|
|
536
|
+
RuntimeError: If uvicorn is not installed
|
|
537
|
+
TypeError: If config_factory doesn't return TaskAppConfig
|
|
538
|
+
"""
|
|
539
|
+
ctx: dict[str, Any] = {"host": host, "port": port, "reload": reload}
|
|
540
|
+
log_info("run_task_app invoked", ctx=ctx)
|
|
541
|
+
|
|
542
|
+
loaded_files = _load_env_files(env_files)
|
|
543
|
+
if loaded_files:
|
|
544
|
+
print(f"[task:server] Loaded environment from: {', '.join(loaded_files)}", flush=True)
|
|
545
|
+
|
|
546
|
+
config = config_factory()
|
|
547
|
+
# Defensive: ensure the factory produced a valid TaskAppConfig to avoid
|
|
548
|
+
# confusing attribute errors later in the boot sequence.
|
|
549
|
+
if not isinstance(config, TaskAppConfig): # type: ignore[arg-type]
|
|
550
|
+
raise TypeError(
|
|
551
|
+
f"Task app config_factory must return TaskAppConfig, got {type(config).__name__}"
|
|
552
|
+
)
|
|
553
|
+
app = create_task_app(config)
|
|
554
|
+
|
|
555
|
+
try:
|
|
556
|
+
import uvicorn
|
|
557
|
+
except ImportError as exc: # pragma: no cover - uvicorn optional
|
|
558
|
+
raise RuntimeError("uvicorn must be installed to run the task app locally") from exc
|
|
559
|
+
|
|
560
|
+
print(f"[task:server] Starting '{config.app_id}' on {host}:{port}", flush=True)
|
|
561
|
+
|
|
562
|
+
# Record local service before starting
|
|
563
|
+
try:
|
|
564
|
+
import os
|
|
565
|
+
|
|
566
|
+
from synth_ai.cli.lib.tunnel_records import record_service
|
|
567
|
+
local_url = f"http://{host if host not in ('0.0.0.0', '::') else '127.0.0.1'}:{port}"
|
|
568
|
+
# Try to get current process PID
|
|
569
|
+
pid: int | None = os.getpid()
|
|
570
|
+
record_service(
|
|
571
|
+
url=local_url,
|
|
572
|
+
port=port,
|
|
573
|
+
service_type="local",
|
|
574
|
+
local_host=host if host not in ('0.0.0.0', '::') else '127.0.0.1',
|
|
575
|
+
app_id=config.app_id,
|
|
576
|
+
pid=pid,
|
|
577
|
+
)
|
|
578
|
+
except Exception:
|
|
579
|
+
pass # Fail silently - records are optional
|
|
580
|
+
|
|
581
|
+
try:
|
|
582
|
+
uvicorn.run(app, host=host, port=port, reload=reload)
|
|
583
|
+
finally:
|
|
584
|
+
# Clean up record when server exits
|
|
585
|
+
try:
|
|
586
|
+
from synth_ai.cli.lib.tunnel_records import remove_service_record
|
|
587
|
+
remove_service_record(port)
|
|
588
|
+
except Exception:
|
|
589
|
+
pass
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
def run_server_background(
|
|
593
|
+
app: Any,
|
|
594
|
+
port: int,
|
|
595
|
+
host: str = "0.0.0.0",
|
|
596
|
+
) -> threading.Thread:
|
|
597
|
+
"""Start uvicorn server in a background daemon thread.
|
|
598
|
+
|
|
599
|
+
For manual control over task app lifecycle. If you want automatic
|
|
600
|
+
tunnel management, use InProcessTaskApp instead.
|
|
601
|
+
|
|
602
|
+
Args:
|
|
603
|
+
app: ASGI/FastAPI application
|
|
604
|
+
port: Port to bind
|
|
605
|
+
host: Host to bind (default 0.0.0.0 for tunnel access)
|
|
606
|
+
|
|
607
|
+
Returns:
|
|
608
|
+
Daemon thread running the server (stops when main process exits)
|
|
609
|
+
|
|
610
|
+
Example:
|
|
611
|
+
from synth_ai.sdk.task import run_server_background
|
|
612
|
+
from synth_ai.sdk.tunnels import wait_for_health_check
|
|
613
|
+
|
|
614
|
+
thread = run_server_background(my_app, port=8001)
|
|
615
|
+
await wait_for_health_check("localhost", 8001, api_key)
|
|
616
|
+
"""
|
|
617
|
+
import asyncio
|
|
618
|
+
import threading
|
|
619
|
+
|
|
620
|
+
import uvicorn
|
|
621
|
+
|
|
622
|
+
def serve() -> None:
|
|
623
|
+
config = uvicorn.Config(app, host=host, port=port, log_level="warning")
|
|
624
|
+
server = uvicorn.Server(config)
|
|
625
|
+
loop = asyncio.new_event_loop()
|
|
626
|
+
asyncio.set_event_loop(loop)
|
|
627
|
+
loop.run_until_complete(server.serve())
|
|
628
|
+
|
|
629
|
+
thread = threading.Thread(target=serve, daemon=True, name=f"uvicorn-{port}")
|
|
630
|
+
thread.start()
|
|
631
|
+
return thread
|