synth-ai 0.2.8.dev2__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/{demos → cli/demo_apps}/core/cli.py +783 -441
- 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 +75 -37
- 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/{demos → cli/demo_apps}/demo_task_apps/math/_common.py +1 -2
- 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} +16 -4
- 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 -108
- 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.8.dev2.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 -144
- synth_ai/cli/legacy_root_backup.py +0 -470
- synth_ai/cli/man.py +0 -106
- synth_ai/cli/rl_demo.py +0 -202
- synth_ai/cli/status.py +0 -133
- synth_ai/config/base_url.py +0 -107
- 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/demo_task_apps/__init__.py +0 -1
- synth_ai/demos/demo_task_apps/math/config.toml +0 -129
- synth_ai/demos/demo_task_apps/math/deploy_task_app.sh +0 -22
- synth_ai/demos/demo_task_apps/math/modal_task_app.py +0 -415
- 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 -738
- 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 -98
- 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/handshake.py +0 -63
- synth_ai/http.py +0 -26
- synth_ai/http_client.py +0 -104
- 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 -225
- 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 -142
- synth_ai/v0/tracing/context.py +0 -146
- synth_ai/v0/tracing/decorators.py +0 -682
- synth_ai/v0/tracing/events/__init__.py +0 -0
- synth_ai/v0/tracing/events/manage.py +0 -147
- synth_ai/v0/tracing/events/scope.py +0 -86
- synth_ai/v0/tracing/events/store.py +0 -228
- synth_ai/v0/tracing/immediate_client.py +0 -151
- synth_ai/v0/tracing/local.py +0 -18
- synth_ai/v0/tracing/log_client_base.py +0 -73
- synth_ai/v0/tracing/retry_queue.py +0 -186
- synth_ai/v0/tracing/trackers.py +0 -515
- synth_ai/v0/tracing/upload.py +0 -512
- synth_ai/v0/tracing/utils.py +0 -9
- synth_ai/v0/tracing_v1/__init__.py +0 -16
- synth_ai/v0/tracing_v1/abstractions.py +0 -224
- synth_ai/v0/tracing_v1/base_client.py +0 -91
- synth_ai/v0/tracing_v1/client_manager.py +0 -131
- synth_ai/v0/tracing_v1/config.py +0 -142
- synth_ai/v0/tracing_v1/context.py +0 -146
- synth_ai/v0/tracing_v1/decorators.py +0 -703
- synth_ai/v0/tracing_v1/events/__init__.py +0 -0
- synth_ai/v0/tracing_v1/events/manage.py +0 -147
- synth_ai/v0/tracing_v1/events/scope.py +0 -86
- synth_ai/v0/tracing_v1/events/store.py +0 -228
- synth_ai/v0/tracing_v1/immediate_client.py +0 -151
- synth_ai/v0/tracing_v1/local.py +0 -18
- synth_ai/v0/tracing_v1/log_client_base.py +0 -73
- synth_ai/v0/tracing_v1/retry_queue.py +0 -186
- synth_ai/v0/tracing_v1/trackers.py +0 -515
- synth_ai/v0/tracing_v1/upload.py +0 -527
- synth_ai/v0/tracing_v1/utils.py +0 -9
- synth_ai/zyk/__init__.py +0 -30
- synth_ai-0.2.8.dev2.dist-info/METADATA +0 -129
- synth_ai-0.2.8.dev2.dist-info/RECORD +0 -420
- /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.8.dev2.dist-info → synth_ai-0.4.3.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.8.dev2.dist-info → synth_ai-0.4.3.dist-info}/licenses/LICENSE +0 -0
- {synth_ai-0.2.8.dev2.dist-info → synth_ai-0.4.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""SQLAlchemy database utilities for the experiment queue."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from typing import Iterator
|
|
7
|
+
|
|
8
|
+
from sqlalchemy import create_engine, text
|
|
9
|
+
from sqlalchemy.engine import Engine
|
|
10
|
+
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
|
|
11
|
+
|
|
12
|
+
from .config import load_config
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Base(DeclarativeBase):
|
|
16
|
+
"""Declarative base for experiment queue ORM models."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_engine: Engine | None = None
|
|
20
|
+
_session_factory: sessionmaker[Session] | None = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_engine() -> Engine:
|
|
24
|
+
"""Get (or lazily create) the SQLAlchemy engine."""
|
|
25
|
+
global _engine
|
|
26
|
+
if _engine is None:
|
|
27
|
+
config = load_config()
|
|
28
|
+
# Enable WAL mode for SQLite to allow concurrent reads/writes
|
|
29
|
+
# This is critical for Celery broker + our ORM to work together
|
|
30
|
+
connect_args = {
|
|
31
|
+
"check_same_thread": False,
|
|
32
|
+
"timeout": 5.0, # 5 second timeout - fast enough but allows WAL mode to work
|
|
33
|
+
}
|
|
34
|
+
# Enable WAL mode via PRAGMA after connection
|
|
35
|
+
def _enable_wal(dbapi_conn, connection_record):
|
|
36
|
+
# dbapi_conn is the raw sqlite3 connection, not SQLAlchemy
|
|
37
|
+
dbapi_conn.execute("PRAGMA journal_mode=WAL")
|
|
38
|
+
dbapi_conn.execute("PRAGMA synchronous=NORMAL")
|
|
39
|
+
|
|
40
|
+
_engine = create_engine(
|
|
41
|
+
config.sqlalchemy_url,
|
|
42
|
+
echo=False,
|
|
43
|
+
future=True,
|
|
44
|
+
connect_args=connect_args,
|
|
45
|
+
pool_pre_ping=True,
|
|
46
|
+
poolclass=None, # Use default pool
|
|
47
|
+
)
|
|
48
|
+
# Register event listener to enable WAL mode on each connection
|
|
49
|
+
from sqlalchemy import event
|
|
50
|
+
event.listen(_engine, "connect", _enable_wal)
|
|
51
|
+
return _engine
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_session() -> Session:
|
|
55
|
+
"""Return a new Session bound to the shared engine."""
|
|
56
|
+
global _session_factory
|
|
57
|
+
if _session_factory is None:
|
|
58
|
+
_session_factory = sessionmaker(
|
|
59
|
+
bind=get_engine(),
|
|
60
|
+
class_=Session,
|
|
61
|
+
expire_on_commit=False,
|
|
62
|
+
autoflush=False,
|
|
63
|
+
future=True,
|
|
64
|
+
)
|
|
65
|
+
return _session_factory()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def init_db() -> None:
|
|
69
|
+
"""Create tables if they do not exist and ensure WAL mode is enabled.
|
|
70
|
+
|
|
71
|
+
This initializes the application database (SQLite) for experiment queue data.
|
|
72
|
+
Celery broker uses Redis, so no SQLite locking conflicts.
|
|
73
|
+
"""
|
|
74
|
+
engine = get_engine()
|
|
75
|
+
|
|
76
|
+
# Enable WAL mode on the database file before creating tables
|
|
77
|
+
# This must happen before Celery's broker connection tries to use it
|
|
78
|
+
# Use multiple connections to ensure WAL mode is persistent
|
|
79
|
+
with engine.connect() as conn:
|
|
80
|
+
# Enable WAL mode (allows concurrent reads/writes)
|
|
81
|
+
result = conn.execute(text("PRAGMA journal_mode=WAL"))
|
|
82
|
+
wal_result = result.scalar()
|
|
83
|
+
if wal_result != "wal":
|
|
84
|
+
# Database might be locked or in use - try again
|
|
85
|
+
import time
|
|
86
|
+
time.sleep(0.1)
|
|
87
|
+
result = conn.execute(text("PRAGMA journal_mode=WAL"))
|
|
88
|
+
wal_result = result.scalar()
|
|
89
|
+
conn.execute(text("PRAGMA synchronous=NORMAL"))
|
|
90
|
+
conn.execute(text("PRAGMA busy_timeout=5000")) # 5 seconds - allows concurrent access
|
|
91
|
+
conn.commit()
|
|
92
|
+
|
|
93
|
+
# Verify WAL mode is enabled
|
|
94
|
+
if wal_result != "wal":
|
|
95
|
+
import warnings
|
|
96
|
+
warnings.warn(
|
|
97
|
+
f"WAL mode not enabled! Got: {wal_result}. "
|
|
98
|
+
f"This may cause SQLite locking errors with Celery.",
|
|
99
|
+
RuntimeWarning,
|
|
100
|
+
stacklevel=2,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Create our application tables
|
|
104
|
+
Base.metadata.create_all(engine)
|
|
105
|
+
|
|
106
|
+
# Migrate schema: add status_json column if it doesn't exist
|
|
107
|
+
with engine.begin() as conn: # Use begin() to ensure transaction is committed
|
|
108
|
+
# Check if table exists first
|
|
109
|
+
table_exists = conn.execute(text(
|
|
110
|
+
"SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='experiment_jobs'"
|
|
111
|
+
)).scalar() > 0
|
|
112
|
+
|
|
113
|
+
if table_exists:
|
|
114
|
+
# Check if status_json column exists
|
|
115
|
+
result = conn.execute(text(
|
|
116
|
+
"SELECT COUNT(*) FROM pragma_table_info('experiment_jobs') WHERE name='status_json'"
|
|
117
|
+
))
|
|
118
|
+
column_exists = result.scalar() > 0
|
|
119
|
+
|
|
120
|
+
if not column_exists:
|
|
121
|
+
# Add status_json column
|
|
122
|
+
conn.execute(text(
|
|
123
|
+
"ALTER TABLE experiment_jobs ADD COLUMN status_json TEXT"
|
|
124
|
+
))
|
|
125
|
+
|
|
126
|
+
# Migrate schema: create job_execution_logs table if it doesn't exist
|
|
127
|
+
with engine.connect() as conn:
|
|
128
|
+
# Check if job_execution_logs table exists
|
|
129
|
+
result = conn.execute(text(
|
|
130
|
+
"SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='job_execution_logs'"
|
|
131
|
+
))
|
|
132
|
+
table_exists = result.scalar() > 0
|
|
133
|
+
|
|
134
|
+
if not table_exists:
|
|
135
|
+
# Create job_execution_logs table
|
|
136
|
+
conn.execute(text("""
|
|
137
|
+
CREATE TABLE job_execution_logs (
|
|
138
|
+
log_id VARCHAR(64) PRIMARY KEY,
|
|
139
|
+
job_id VARCHAR(64) NOT NULL,
|
|
140
|
+
command TEXT NOT NULL,
|
|
141
|
+
working_directory TEXT NOT NULL,
|
|
142
|
+
returncode INTEGER NOT NULL,
|
|
143
|
+
stdout TEXT NOT NULL DEFAULT '',
|
|
144
|
+
stderr TEXT NOT NULL DEFAULT '',
|
|
145
|
+
python_executable VARCHAR(255),
|
|
146
|
+
environment_keys TEXT,
|
|
147
|
+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
148
|
+
FOREIGN KEY (job_id) REFERENCES experiment_jobs(job_id) ON DELETE CASCADE
|
|
149
|
+
)
|
|
150
|
+
"""))
|
|
151
|
+
# Create indexes
|
|
152
|
+
conn.execute(text("CREATE INDEX idx_job_execution_logs_job ON job_execution_logs(job_id)"))
|
|
153
|
+
conn.execute(text("CREATE INDEX idx_job_execution_logs_returncode ON job_execution_logs(returncode)"))
|
|
154
|
+
conn.execute(text("CREATE INDEX idx_job_execution_logs_created ON job_execution_logs(created_at)"))
|
|
155
|
+
conn.commit()
|
|
156
|
+
|
|
157
|
+
# Force WAL mode one more time after table creation
|
|
158
|
+
# This ensures it's set even if table creation changed something
|
|
159
|
+
with engine.connect() as conn:
|
|
160
|
+
conn.execute(text("PRAGMA journal_mode=WAL"))
|
|
161
|
+
conn.commit()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@contextmanager
|
|
165
|
+
def session_scope() -> Iterator[Session]:
|
|
166
|
+
"""Provide a transactional scope for DB operations."""
|
|
167
|
+
session = get_session()
|
|
168
|
+
try:
|
|
169
|
+
yield session
|
|
170
|
+
session.commit()
|
|
171
|
+
except Exception:
|
|
172
|
+
session.rollback()
|
|
173
|
+
raise
|
|
174
|
+
finally:
|
|
175
|
+
session.close()
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Utility helpers to enqueue Celery tasks while respecting parallelism limits."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
from sqlalchemy import Select, func, select
|
|
10
|
+
from sqlalchemy.orm import Session
|
|
11
|
+
|
|
12
|
+
# Clear config cache if env vars are set (must happen before other imports)
|
|
13
|
+
if os.getenv("EXPERIMENT_QUEUE_DB_PATH") or os.getenv("EXPERIMENT_QUEUE_TRAIN_CMD"):
|
|
14
|
+
from . import config as queue_config
|
|
15
|
+
|
|
16
|
+
queue_config.reset_config_cache()
|
|
17
|
+
|
|
18
|
+
from .celery_app import get_celery_app
|
|
19
|
+
from .models import Experiment, ExperimentJob, ExperimentJobStatus
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
TASK_NAME = "synth_ai.cli.local.experiment_queue.run_experiment_job"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _active_jobs_query(experiment_id: str) -> Select[tuple[int]]:
|
|
27
|
+
"""Build a SQLAlchemy query to count active jobs for an experiment.
|
|
28
|
+
|
|
29
|
+
Counts jobs that are:
|
|
30
|
+
- QUEUED or RUNNING status
|
|
31
|
+
- Have a Celery task ID assigned (dispatched)
|
|
32
|
+
- Not yet completed (completed_at is None)
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
experiment_id: Experiment identifier
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
SQLAlchemy Select query that returns a count
|
|
39
|
+
"""
|
|
40
|
+
return (
|
|
41
|
+
select(func.count(ExperimentJob.job_id))
|
|
42
|
+
.where(
|
|
43
|
+
ExperimentJob.experiment_id == experiment_id,
|
|
44
|
+
ExperimentJob.status.in_(
|
|
45
|
+
[ExperimentJobStatus.RUNNING, ExperimentJobStatus.QUEUED]
|
|
46
|
+
),
|
|
47
|
+
ExperimentJob.celery_task_id.is_not(None),
|
|
48
|
+
ExperimentJob.completed_at.is_(None),
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def dispatch_available_jobs(session: Session, experiment_id: str) -> list[str]:
|
|
54
|
+
"""Send ready jobs to Celery while honoring experiment parallelism."""
|
|
55
|
+
experiment = session.get(Experiment, experiment_id)
|
|
56
|
+
if not experiment:
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
limit = max(experiment.parallelism_limit or 1, 1)
|
|
60
|
+
active = session.execute(_active_jobs_query(experiment_id)).scalar_one()
|
|
61
|
+
remaining_slots = max(limit - active, 0)
|
|
62
|
+
if remaining_slots <= 0:
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
ready_jobs: List[ExperimentJob] = (
|
|
66
|
+
session.query(ExperimentJob)
|
|
67
|
+
.filter(
|
|
68
|
+
ExperimentJob.experiment_id == experiment_id,
|
|
69
|
+
ExperimentJob.status == ExperimentJobStatus.QUEUED,
|
|
70
|
+
ExperimentJob.celery_task_id.is_(None),
|
|
71
|
+
)
|
|
72
|
+
.order_by(ExperimentJob.created_at.asc())
|
|
73
|
+
.limit(remaining_slots)
|
|
74
|
+
.all()
|
|
75
|
+
)
|
|
76
|
+
if not ready_jobs:
|
|
77
|
+
return []
|
|
78
|
+
|
|
79
|
+
app = get_celery_app()
|
|
80
|
+
# Get broker URL for logging (may not be available in test stubs)
|
|
81
|
+
try:
|
|
82
|
+
broker_url = app.conf.broker_url
|
|
83
|
+
except AttributeError:
|
|
84
|
+
broker_url = "unknown"
|
|
85
|
+
logger.info(
|
|
86
|
+
"Dispatching %d jobs using Celery broker: %s",
|
|
87
|
+
len(ready_jobs),
|
|
88
|
+
broker_url,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Extract job IDs before committing session
|
|
92
|
+
job_ids = [job.job_id for job in ready_jobs]
|
|
93
|
+
|
|
94
|
+
# Commit session before calling send_task
|
|
95
|
+
# Redis broker handles concurrency natively, no locking issues
|
|
96
|
+
session.flush()
|
|
97
|
+
session.commit()
|
|
98
|
+
|
|
99
|
+
dispatched: list[str] = []
|
|
100
|
+
for job_id in job_ids:
|
|
101
|
+
# send_task sends message to Redis broker
|
|
102
|
+
result = app.send_task(TASK_NAME, args=[job_id])
|
|
103
|
+
|
|
104
|
+
# Update celery_task_id in a new transaction
|
|
105
|
+
job = session.query(ExperimentJob).filter(ExperimentJob.job_id == job_id).first()
|
|
106
|
+
if job:
|
|
107
|
+
job.celery_task_id = result.id
|
|
108
|
+
logger.debug(
|
|
109
|
+
"Dispatched job %s with task_id %s",
|
|
110
|
+
job_id,
|
|
111
|
+
result.id,
|
|
112
|
+
)
|
|
113
|
+
dispatched.append(job_id)
|
|
114
|
+
|
|
115
|
+
# Flush to persist celery_task_id updates
|
|
116
|
+
session.flush()
|
|
117
|
+
# Note: Task message is sent to Redis broker
|
|
118
|
+
# The final commit happens when session_scope exits in create_experiment()
|
|
119
|
+
return dispatched
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""SQLAlchemy ORM models for the experiment queue."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import enum
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from sqlalchemy import (
|
|
10
|
+
JSON,
|
|
11
|
+
DateTime,
|
|
12
|
+
Float,
|
|
13
|
+
ForeignKey,
|
|
14
|
+
Index,
|
|
15
|
+
Integer,
|
|
16
|
+
String,
|
|
17
|
+
Text,
|
|
18
|
+
UniqueConstraint,
|
|
19
|
+
func,
|
|
20
|
+
)
|
|
21
|
+
from sqlalchemy import (
|
|
22
|
+
Enum as SAEnum,
|
|
23
|
+
)
|
|
24
|
+
from sqlalchemy.ext.mutable import MutableDict
|
|
25
|
+
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
26
|
+
|
|
27
|
+
from .database import Base
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ExperimentStatus(str, enum.Enum):
|
|
31
|
+
QUEUED = "queued"
|
|
32
|
+
RUNNING = "running"
|
|
33
|
+
COMPLETED = "completed"
|
|
34
|
+
FAILED = "failed"
|
|
35
|
+
CANCELED = "canceled"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ExperimentJobType(str, enum.Enum):
|
|
39
|
+
GEPA = "gepa"
|
|
40
|
+
MIPRO = "mipro"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ExperimentJobStatus(str, enum.Enum):
|
|
44
|
+
QUEUED = "queued"
|
|
45
|
+
RUNNING = "running"
|
|
46
|
+
COMPLETED = "completed"
|
|
47
|
+
FAILED = "failed"
|
|
48
|
+
CANCELED = "canceled"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TrialStatus(str, enum.Enum):
|
|
52
|
+
PENDING = "pending"
|
|
53
|
+
RUNNING = "running"
|
|
54
|
+
COMPLETED = "completed"
|
|
55
|
+
FAILED = "failed"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Experiment(Base):
|
|
59
|
+
__tablename__ = "experiments"
|
|
60
|
+
|
|
61
|
+
experiment_id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
62
|
+
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
63
|
+
description: Mapped[str | None] = mapped_column(Text())
|
|
64
|
+
status: Mapped[ExperimentStatus] = mapped_column(
|
|
65
|
+
SAEnum(ExperimentStatus, name="experiment_status"),
|
|
66
|
+
default=ExperimentStatus.QUEUED,
|
|
67
|
+
nullable=False,
|
|
68
|
+
)
|
|
69
|
+
parallelism_limit: Mapped[int] = mapped_column(Integer, default=3, nullable=False)
|
|
70
|
+
config_toml: Mapped[str] = mapped_column(Text(), nullable=False)
|
|
71
|
+
metadata_json: Mapped[dict[str, Any]] = mapped_column(
|
|
72
|
+
"metadata",
|
|
73
|
+
MutableDict.as_mutable(JSON),
|
|
74
|
+
default=dict,
|
|
75
|
+
nullable=False,
|
|
76
|
+
)
|
|
77
|
+
error: Mapped[str | None] = mapped_column(Text())
|
|
78
|
+
|
|
79
|
+
created_at: Mapped[datetime] = mapped_column(
|
|
80
|
+
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
81
|
+
)
|
|
82
|
+
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
83
|
+
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
84
|
+
|
|
85
|
+
jobs: Mapped[list[ExperimentJob]] = relationship(
|
|
86
|
+
back_populates="experiment", cascade="all, delete-orphan"
|
|
87
|
+
)
|
|
88
|
+
trials: Mapped[list[Trial]] = relationship(
|
|
89
|
+
back_populates="experiment", cascade="all, delete-orphan"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
__table_args__ = (
|
|
93
|
+
Index("idx_experiments_status", "status"),
|
|
94
|
+
Index("idx_experiments_created", "created_at"),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
class ExperimentJob(Base):
|
|
98
|
+
__tablename__ = "experiment_jobs"
|
|
99
|
+
|
|
100
|
+
job_id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
101
|
+
experiment_id: Mapped[str] = mapped_column(
|
|
102
|
+
String(64), ForeignKey("experiments.experiment_id", ondelete="CASCADE"), nullable=False
|
|
103
|
+
)
|
|
104
|
+
job_type: Mapped[ExperimentJobType] = mapped_column(
|
|
105
|
+
SAEnum(ExperimentJobType, name="experiment_job_type"),
|
|
106
|
+
nullable=False,
|
|
107
|
+
)
|
|
108
|
+
config_path: Mapped[str] = mapped_column(Text(), nullable=False)
|
|
109
|
+
config_overrides: Mapped[dict[str, Any]] = mapped_column(
|
|
110
|
+
MutableDict.as_mutable(JSON), default=dict, nullable=False
|
|
111
|
+
)
|
|
112
|
+
status: Mapped[ExperimentJobStatus] = mapped_column(
|
|
113
|
+
SAEnum(ExperimentJobStatus, name="experiment_job_status"),
|
|
114
|
+
default=ExperimentJobStatus.QUEUED,
|
|
115
|
+
nullable=False,
|
|
116
|
+
)
|
|
117
|
+
celery_task_id: Mapped[str | None] = mapped_column(String(128))
|
|
118
|
+
backend_job_id: Mapped[str | None] = mapped_column(String(128))
|
|
119
|
+
result: Mapped[dict[str, Any] | None] = mapped_column(MutableDict.as_mutable(JSON))
|
|
120
|
+
status_json: Mapped[dict[str, Any] | None] = mapped_column(MutableDict.as_mutable(JSON))
|
|
121
|
+
error: Mapped[str | None] = mapped_column(Text())
|
|
122
|
+
|
|
123
|
+
created_at: Mapped[datetime] = mapped_column(
|
|
124
|
+
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
125
|
+
)
|
|
126
|
+
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
127
|
+
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
128
|
+
|
|
129
|
+
experiment: Mapped[Experiment] = relationship(back_populates="jobs")
|
|
130
|
+
trials: Mapped[list[Trial]] = relationship(back_populates="job")
|
|
131
|
+
execution_logs: Mapped[list[JobExecutionLog]] = relationship(
|
|
132
|
+
back_populates="job", cascade="all, delete-orphan"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
__table_args__ = (
|
|
136
|
+
Index("idx_experiment_jobs_status", "status"),
|
|
137
|
+
Index("idx_experiment_jobs_experiment", "experiment_id"),
|
|
138
|
+
Index("idx_experiment_jobs_celery_task", "celery_task_id"),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class Trial(Base):
|
|
143
|
+
__tablename__ = "trials"
|
|
144
|
+
|
|
145
|
+
trial_id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
146
|
+
experiment_id: Mapped[str] = mapped_column(
|
|
147
|
+
String(64), ForeignKey("experiments.experiment_id", ondelete="CASCADE"), nullable=False
|
|
148
|
+
)
|
|
149
|
+
job_id: Mapped[str | None] = mapped_column(
|
|
150
|
+
String(64), ForeignKey("experiment_jobs.job_id", ondelete="SET NULL")
|
|
151
|
+
)
|
|
152
|
+
trial_number: Mapped[int | None] = mapped_column(Integer)
|
|
153
|
+
system_name: Mapped[str | None] = mapped_column(String(128))
|
|
154
|
+
prompt_id: Mapped[str | None] = mapped_column(String(128))
|
|
155
|
+
session_id: Mapped[str | None] = mapped_column(String(128))
|
|
156
|
+
trace_stored_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
157
|
+
|
|
158
|
+
reward: Mapped[float | None] = mapped_column(Float)
|
|
159
|
+
aggregate_score: Mapped[float | None] = mapped_column(Float)
|
|
160
|
+
rewards: Mapped[dict[str, Any] | None] = mapped_column(MutableDict.as_mutable(JSON))
|
|
161
|
+
metadata_json: Mapped[dict[str, Any]] = mapped_column(
|
|
162
|
+
"metadata",
|
|
163
|
+
MutableDict.as_mutable(JSON),
|
|
164
|
+
default=dict,
|
|
165
|
+
nullable=False,
|
|
166
|
+
)
|
|
167
|
+
status: Mapped[TrialStatus] = mapped_column(
|
|
168
|
+
SAEnum(TrialStatus, name="experiment_trial_status"),
|
|
169
|
+
default=TrialStatus.PENDING,
|
|
170
|
+
nullable=False,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
created_at: Mapped[datetime] = mapped_column(
|
|
174
|
+
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
175
|
+
)
|
|
176
|
+
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
177
|
+
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
178
|
+
|
|
179
|
+
experiment: Mapped[Experiment] = relationship(back_populates="trials")
|
|
180
|
+
job: Mapped[ExperimentJob | None] = relationship(back_populates="trials")
|
|
181
|
+
|
|
182
|
+
__table_args__ = (
|
|
183
|
+
Index("idx_trials_experiment", "experiment_id"),
|
|
184
|
+
Index("idx_trials_job", "job_id"),
|
|
185
|
+
Index("idx_trials_status", "status"),
|
|
186
|
+
Index("idx_trials_reward", "reward"),
|
|
187
|
+
Index("idx_trials_aggregate_score", "aggregate_score"),
|
|
188
|
+
Index("idx_trials_experiment_trial_number", "experiment_id", "trial_number"),
|
|
189
|
+
UniqueConstraint("experiment_id", "trial_number", name="uq_trial_number_per_experiment"),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class JobExecutionLog(Base):
|
|
194
|
+
"""Detailed execution logs for job subprocess runs.
|
|
195
|
+
|
|
196
|
+
Stores full stdout, stderr, command, and environment info for ALL jobs (successful and failed).
|
|
197
|
+
This allows querying failures directly from the database without guessing.
|
|
198
|
+
"""
|
|
199
|
+
__tablename__ = "job_execution_logs"
|
|
200
|
+
|
|
201
|
+
log_id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
202
|
+
job_id: Mapped[str] = mapped_column(
|
|
203
|
+
String(64), ForeignKey("experiment_jobs.job_id", ondelete="CASCADE"), nullable=False
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Execution details
|
|
207
|
+
command: Mapped[str] = mapped_column(Text(), nullable=False) # Full command executed
|
|
208
|
+
working_directory: Mapped[str] = mapped_column(Text(), nullable=False)
|
|
209
|
+
returncode: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
210
|
+
|
|
211
|
+
# Output (stored as Text to handle large outputs)
|
|
212
|
+
stdout: Mapped[str] = mapped_column(Text(), nullable=False, default="")
|
|
213
|
+
stderr: Mapped[str] = mapped_column(Text(), nullable=False, default="")
|
|
214
|
+
|
|
215
|
+
# Environment info (for debugging)
|
|
216
|
+
python_executable: Mapped[str | None] = mapped_column(String(255))
|
|
217
|
+
environment_keys: Mapped[list[str] | None] = mapped_column(JSON) # List of env var keys present
|
|
218
|
+
|
|
219
|
+
# Timestamps
|
|
220
|
+
created_at: Mapped[datetime] = mapped_column(
|
|
221
|
+
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# Relationship
|
|
225
|
+
job: Mapped[ExperimentJob] = relationship(back_populates="execution_logs")
|
|
226
|
+
|
|
227
|
+
__table_args__ = (
|
|
228
|
+
Index("idx_job_execution_logs_job", "job_id"),
|
|
229
|
+
Index("idx_job_execution_logs_returncode", "returncode"),
|
|
230
|
+
Index("idx_job_execution_logs_created", "created_at"),
|
|
231
|
+
)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Type-safe progress information dataclass."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True, slots=True)
|
|
10
|
+
class ProgressInfo:
|
|
11
|
+
"""Type-safe representation of progress information parsed from output.
|
|
12
|
+
|
|
13
|
+
This replaces dict[str, Any] usage in status_tracker.py for better type safety.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
rollouts_completed: int | None = None
|
|
17
|
+
total_rollouts: int | None = None
|
|
18
|
+
best_score: float | None = None
|
|
19
|
+
trials_completed: int | None = None
|
|
20
|
+
|
|
21
|
+
def __post_init__(self) -> None:
|
|
22
|
+
"""Validate progress data after initialization."""
|
|
23
|
+
# Validate rollouts_completed
|
|
24
|
+
if self.rollouts_completed is not None:
|
|
25
|
+
assert isinstance(self.rollouts_completed, int), (
|
|
26
|
+
f"rollouts_completed must be int, got {type(self.rollouts_completed).__name__}"
|
|
27
|
+
)
|
|
28
|
+
assert self.rollouts_completed >= 0, (
|
|
29
|
+
f"rollouts_completed must be >= 0, got {self.rollouts_completed}"
|
|
30
|
+
)
|
|
31
|
+
if self.total_rollouts is not None:
|
|
32
|
+
assert self.rollouts_completed <= self.total_rollouts, (
|
|
33
|
+
f"rollouts_completed ({self.rollouts_completed}) > total_rollouts ({self.total_rollouts})"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Validate total_rollouts
|
|
37
|
+
if self.total_rollouts is not None:
|
|
38
|
+
assert isinstance(self.total_rollouts, int), (
|
|
39
|
+
f"total_rollouts must be int, got {type(self.total_rollouts).__name__}"
|
|
40
|
+
)
|
|
41
|
+
assert self.total_rollouts > 0, (
|
|
42
|
+
f"total_rollouts must be > 0, got {self.total_rollouts}"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Validate best_score
|
|
46
|
+
if self.best_score is not None:
|
|
47
|
+
assert isinstance(self.best_score, int | float), (
|
|
48
|
+
f"best_score must be int | float, got {type(self.best_score).__name__}"
|
|
49
|
+
)
|
|
50
|
+
assert 0 <= self.best_score <= 1, (
|
|
51
|
+
f"best_score must be in [0, 1], got {self.best_score}"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Validate trials_completed
|
|
55
|
+
if self.trials_completed is not None:
|
|
56
|
+
assert isinstance(self.trials_completed, int), (
|
|
57
|
+
f"trials_completed must be int, got {type(self.trials_completed).__name__}"
|
|
58
|
+
)
|
|
59
|
+
assert self.trials_completed >= 0, (
|
|
60
|
+
f"trials_completed must be >= 0, got {self.trials_completed}"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def to_dict(self) -> dict[str, int | float | None]:
|
|
64
|
+
"""Convert to dictionary for compatibility with existing code."""
|
|
65
|
+
return {
|
|
66
|
+
"rollouts_completed": self.rollouts_completed,
|
|
67
|
+
"total_rollouts": self.total_rollouts,
|
|
68
|
+
"best_score": self.best_score,
|
|
69
|
+
"trials_completed": self.trials_completed,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def from_dict(cls, data: dict[str, Any]) -> ProgressInfo:
|
|
74
|
+
"""Create from dictionary with type coercion and validation.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
data: Dictionary with progress information (may have wrong types)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
ProgressInfo instance with validated and coerced types
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
AssertionError: If data cannot be coerced or is invalid
|
|
84
|
+
"""
|
|
85
|
+
# Coerce and validate each field
|
|
86
|
+
rollouts_completed = None
|
|
87
|
+
if "rollouts_completed" in data and data["rollouts_completed"] is not None:
|
|
88
|
+
val = data["rollouts_completed"]
|
|
89
|
+
if isinstance(val, int | float | str):
|
|
90
|
+
try:
|
|
91
|
+
coerced = int(float(val))
|
|
92
|
+
assert coerced >= 0, f"rollouts_completed must be >= 0, got {coerced}"
|
|
93
|
+
rollouts_completed = coerced
|
|
94
|
+
except (ValueError, TypeError, AssertionError) as e:
|
|
95
|
+
raise AssertionError(
|
|
96
|
+
f"Cannot coerce rollouts_completed to int: {val} (type: {type(val).__name__})"
|
|
97
|
+
) from e
|
|
98
|
+
else:
|
|
99
|
+
raise AssertionError(
|
|
100
|
+
f"rollouts_completed must be int | float | str, got {type(val).__name__}: {val}"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
total_rollouts = None
|
|
104
|
+
if "total_rollouts" in data and data["total_rollouts"] is not None:
|
|
105
|
+
val = data["total_rollouts"]
|
|
106
|
+
if isinstance(val, int | float | str):
|
|
107
|
+
try:
|
|
108
|
+
total_rollouts = int(float(val))
|
|
109
|
+
except (ValueError, TypeError) as e:
|
|
110
|
+
raise AssertionError(
|
|
111
|
+
f"Cannot coerce total_rollouts to int: {val} (type: {type(val).__name__})"
|
|
112
|
+
) from e
|
|
113
|
+
else:
|
|
114
|
+
raise AssertionError(
|
|
115
|
+
f"total_rollouts must be int | float | str, got {type(val).__name__}: {val}"
|
|
116
|
+
)
|
|
117
|
+
if total_rollouts is not None:
|
|
118
|
+
assert total_rollouts > 0, f"total_rollouts must be > 0, got {total_rollouts}"
|
|
119
|
+
|
|
120
|
+
best_score = None
|
|
121
|
+
if "best_score" in data and data["best_score"] is not None:
|
|
122
|
+
val = data["best_score"]
|
|
123
|
+
if isinstance(val, int | float | str):
|
|
124
|
+
try:
|
|
125
|
+
coerced = float(val)
|
|
126
|
+
assert 0 <= coerced <= 1, f"best_score must be in [0, 1], got {coerced}"
|
|
127
|
+
best_score = coerced
|
|
128
|
+
except (ValueError, TypeError, AssertionError) as e:
|
|
129
|
+
raise AssertionError(
|
|
130
|
+
f"Cannot coerce best_score to float: {val} (type: {type(val).__name__})"
|
|
131
|
+
) from e
|
|
132
|
+
else:
|
|
133
|
+
raise AssertionError(
|
|
134
|
+
f"best_score must be int | float | str, got {type(val).__name__}: {val}"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
trials_completed = None
|
|
138
|
+
if "trials_completed" in data and data["trials_completed"] is not None:
|
|
139
|
+
val = data["trials_completed"]
|
|
140
|
+
if isinstance(val, int | float | str):
|
|
141
|
+
try:
|
|
142
|
+
coerced = int(float(val))
|
|
143
|
+
assert coerced >= 0, f"trials_completed must be >= 0, got {coerced}"
|
|
144
|
+
trials_completed = coerced
|
|
145
|
+
except (ValueError, TypeError, AssertionError) as e:
|
|
146
|
+
raise AssertionError(
|
|
147
|
+
f"Cannot coerce trials_completed to int: {val} (type: {type(val).__name__})"
|
|
148
|
+
) from e
|
|
149
|
+
else:
|
|
150
|
+
raise AssertionError(
|
|
151
|
+
f"trials_completed must be int | float | str, got {type(val).__name__}: {val}"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return cls(
|
|
155
|
+
rollouts_completed=rollouts_completed,
|
|
156
|
+
total_rollouts=total_rollouts,
|
|
157
|
+
best_score=best_score,
|
|
158
|
+
trials_completed=trials_completed,
|
|
159
|
+
)
|
|
160
|
+
|