synth-ai 0.2.9.dev7__py3-none-any.whl → 0.2.9.dev8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synth-ai might be problematic. Click here for more details.
- examples/__init__.py +16 -0
- examples/crafter_debug_render.py +8 -11
- examples/qwen_coder/README.md +102 -0
- examples/qwen_coder/_shared.py +113 -0
- examples/qwen_coder/configs/coder_lora_30b.toml +61 -0
- examples/qwen_coder/configs/coder_lora_4b.toml +57 -0
- examples/qwen_coder/configs/coder_lora_small.toml +58 -0
- examples/qwen_coder/generate_dataset.py +98 -0
- examples/qwen_coder/infer_ft_smoke.py +64 -0
- examples/qwen_coder/infer_prod_proxy.py +73 -0
- examples/qwen_coder/infer_via_synth.py +87 -0
- examples/qwen_coder/scripts/infer_coder.sh +18 -0
- examples/qwen_coder/scripts/train_coder_30b.sh +21 -0
- examples/qwen_coder/sft_full_17b.py +103 -0
- examples/qwen_coder/sft_lora_30b.py +110 -0
- examples/qwen_coder/subset_jsonl.py +38 -0
- examples/qwen_coder/validate_jsonl.py +59 -0
- examples/rl/run_eval.py +36 -37
- examples/rl/run_rl_and_save.py +5 -5
- examples/rl/task_app/math_single_step.py +65 -43
- examples/rl/task_app/math_task_app.py +3 -3
- examples/sft/README.md +139 -0
- examples/sft/configs/crafter_fft_qwen0p6b.toml +44 -0
- examples/sft/configs/crafter_lora_qwen0p6b.toml +45 -0
- examples/sft/evaluate.py +117 -0
- examples/sft/export_dataset.py +117 -0
- examples/sft/generate_traces.py +162 -0
- examples/swe/__init__.py +12 -0
- examples/swe/task_app/README.md +105 -0
- examples/swe/task_app/__init__.py +2 -0
- examples/swe/task_app/grpo_swe_mini.py +571 -0
- examples/swe/task_app/grpo_swe_mini_task_app.py +136 -0
- examples/swe/task_app/hosted/README.md +173 -0
- examples/swe/task_app/hosted/__init__.py +5 -0
- examples/swe/task_app/hosted/branching.py +143 -0
- examples/swe/task_app/hosted/environment_routes.py +1289 -0
- examples/swe/task_app/hosted/envs/__init__.py +1 -0
- examples/swe/task_app/hosted/envs/crafter/__init__.py +6 -0
- examples/swe/task_app/hosted/envs/crafter/app.py +1 -0
- examples/swe/task_app/hosted/envs/crafter/environment.py +522 -0
- examples/swe/task_app/hosted/envs/crafter/policy.py +478 -0
- examples/swe/task_app/hosted/envs/crafter/react_agent.py +108 -0
- examples/swe/task_app/hosted/envs/crafter/shared.py +305 -0
- examples/swe/task_app/hosted/envs/crafter/tools.py +47 -0
- examples/swe/task_app/hosted/envs/mini_swe/__init__.py +8 -0
- examples/swe/task_app/hosted/envs/mini_swe/environment.py +1164 -0
- examples/swe/task_app/hosted/envs/mini_swe/policy.py +355 -0
- examples/swe/task_app/hosted/envs/mini_swe/shared.py +83 -0
- examples/swe/task_app/hosted/envs/mini_swe/tools.py +96 -0
- examples/swe/task_app/hosted/hosted_app.py +204 -0
- examples/swe/task_app/hosted/inference/__init__.py +5 -0
- examples/swe/task_app/hosted/inference/openai_client.py +618 -0
- examples/swe/task_app/hosted/main.py +100 -0
- examples/swe/task_app/hosted/policy_routes.py +1079 -0
- examples/swe/task_app/hosted/registry.py +195 -0
- examples/swe/task_app/hosted/rollout.py +1869 -0
- examples/swe/task_app/hosted/storage/__init__.py +5 -0
- examples/swe/task_app/hosted/storage/volume.py +211 -0
- examples/swe/task_app/hosted/test_agents.py +161 -0
- examples/swe/task_app/hosted/test_service.py +137 -0
- examples/swe/task_app/hosted/utils.py +62 -0
- examples/vlm/README.md +68 -0
- examples/vlm/configs/crafter_vlm_gpt4o.toml +44 -0
- examples/vlm/crafter_image_only_agent.py +207 -0
- examples/vlm/crafter_openai_vlm_agent.py +277 -0
- examples/vlm/filter_image_rows.py +63 -0
- examples/vlm/run_crafter_vlm_benchmark.py +316 -0
- examples/warming_up_to_rl/analyze_trace_db.py +5 -5
- examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +11 -1
- examples/warming_up_to_rl/export_trace_sft.py +78 -21
- examples/warming_up_to_rl/groq_test.py +4 -4
- examples/warming_up_to_rl/manage_secrets.py +13 -18
- examples/warming_up_to_rl/run_eval.py +42 -44
- examples/warming_up_to_rl/run_fft_and_save.py +11 -16
- examples/warming_up_to_rl/run_local_rollout.py +1 -3
- examples/warming_up_to_rl/run_local_rollout_modal.py +2 -4
- examples/warming_up_to_rl/run_local_rollout_parallel.py +1 -4
- examples/warming_up_to_rl/run_local_rollout_traced.py +3 -5
- examples/warming_up_to_rl/run_rl_and_save.py +5 -6
- examples/warming_up_to_rl/run_rollout_remote.py +8 -10
- examples/warming_up_to_rl/task_app/README.md +6 -2
- examples/warming_up_to_rl/task_app/grpo_crafter.py +234 -35
- examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +2 -3
- examples/warming_up_to_rl/task_app/synth_envs_hosted/__init__.py +1 -1
- examples/warming_up_to_rl/task_app/synth_envs_hosted/branching.py +9 -11
- examples/warming_up_to_rl/task_app/synth_envs_hosted/environment_routes.py +131 -114
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +101 -41
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +73 -51
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +14 -6
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +16 -16
- examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +32 -34
- examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +94 -31
- examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +0 -2
- examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +303 -203
- examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +21 -23
- examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +328 -225
- examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +13 -13
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +1 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +1 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +4 -3
- synth/__init__.py +14 -0
- synth_ai/__init__.py +26 -4
- synth_ai/api/models/supported.py +376 -0
- synth_ai/api/train/builders.py +128 -21
- synth_ai/api/train/cli.py +80 -64
- synth_ai/api/train/config_finder.py +7 -2
- synth_ai/api/train/env_resolver.py +1 -1
- synth_ai/api/train/pollers.py +2 -1
- synth_ai/api/train/supported_algos.py +139 -0
- synth_ai/api/train/task_app.py +1 -2
- synth_ai/api/train/utils.py +13 -44
- synth_ai/cli/__init__.py +8 -0
- synth_ai/cli/_modal_wrapper.py +28 -0
- synth_ai/cli/_typer_patch.py +49 -0
- synth_ai/cli/balance.py +1 -2
- synth_ai/cli/calc.py +1 -1
- synth_ai/cli/demo.py +2 -1
- synth_ai/cli/recent.py +2 -2
- synth_ai/cli/rl_demo.py +2 -1
- synth_ai/cli/root.py +11 -13
- synth_ai/cli/status.py +2 -2
- synth_ai/cli/task_apps.py +529 -179
- synth_ai/cli/traces.py +6 -4
- synth_ai/cli/watch.py +12 -18
- synth_ai/demo_registry.py +1 -1
- synth_ai/demos/core/cli.py +36 -43
- synth_ai/demos/demo_task_apps/__init__.py +3 -3
- synth_ai/demos/demo_task_apps/core.py +17 -25
- synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +3 -4
- synth_ai/demos/demo_task_apps/math/app.py +2 -1
- synth_ai/demos/demo_task_apps/math/deploy_modal.py +3 -4
- synth_ai/demos/demo_task_apps/math/modal_task_app.py +16 -18
- synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -1
- synth_ai/environments/examples/crafter_classic/environment.py +76 -1
- synth_ai/environments/reproducibility/tree.py +2 -5
- synth_ai/environments/service/app.py +11 -12
- synth_ai/environments/service/core_routes.py +4 -7
- synth_ai/environments/stateful/engine.py +1 -1
- synth_ai/environments/tasks/core.py +1 -0
- synth_ai/environments/tasks/filters.py +5 -6
- synth_ai/environments/tasks/utils.py +4 -5
- synth_ai/handshake.py +9 -9
- synth_ai/http.py +1 -1
- synth_ai/http_client.py +18 -10
- synth_ai/inference/client.py +15 -5
- synth_ai/jobs/client.py +78 -83
- synth_ai/learning/__init__.py +41 -6
- synth_ai/learning/algorithms.py +14 -0
- synth_ai/learning/client.py +91 -24
- synth_ai/learning/config.py +2 -38
- synth_ai/learning/ft_client.py +4 -59
- synth_ai/learning/health.py +5 -6
- synth_ai/learning/jobs.py +31 -47
- synth_ai/{rl → learning/rl}/__init__.py +14 -4
- synth_ai/learning/rl/client.py +267 -0
- synth_ai/learning/rl/config.py +31 -0
- synth_ai/{rl → learning/rl}/contracts.py +5 -8
- synth_ai/{rl → learning/rl}/env_keys.py +39 -15
- synth_ai/learning/rl/secrets.py +13 -0
- synth_ai/learning/rl_client.py +2 -281
- synth_ai/learning/sft/__init__.py +29 -0
- synth_ai/learning/sft/client.py +68 -0
- synth_ai/learning/sft/config.py +270 -0
- synth_ai/learning/sft/data.py +295 -0
- synth_ai/learning/sse.py +25 -24
- synth_ai/learning/validators.py +25 -28
- synth_ai/lm/__init__.py +21 -47
- synth_ai/main.py +4 -0
- synth_ai/task/__init__.py +25 -27
- synth_ai/task/apps/__init__.py +7 -8
- synth_ai/task/auth.py +8 -8
- synth_ai/task/client.py +14 -14
- synth_ai/task/contracts.py +36 -35
- synth_ai/task/datasets.py +6 -5
- synth_ai/task/errors.py +10 -10
- synth_ai/task/health.py +17 -9
- synth_ai/task/json.py +58 -23
- synth_ai/task/proxy.py +13 -9
- synth_ai/task/rubrics.py +16 -15
- synth_ai/task/server.py +12 -12
- synth_ai/task/tracing_utils.py +4 -4
- synth_ai/task/vendors.py +5 -6
- synth_ai/tracing_v3/__init__.py +2 -0
- synth_ai/tracing_v3/abstractions.py +21 -4
- synth_ai/tracing_v3/decorators.py +18 -16
- synth_ai/tracing_v3/hooks.py +5 -5
- synth_ai/tracing_v3/llm_call_record_helpers.py +6 -6
- synth_ai/tracing_v3/session_tracer.py +40 -14
- synth_ai/tracing_v3/storage/base.py +85 -0
- synth_ai/tracing_v3/storage/config.py +21 -8
- synth_ai/tracing_v3/storage/factory.py +10 -7
- synth_ai/tracing_v3/storage/utils.py +4 -2
- synth_ai/tracing_v3/turso/daemon.py +7 -2
- synth_ai/tracing_v3/turso/models.py +2 -2
- synth_ai/tracing_v3/turso/native_manager.py +1173 -0
- synth_ai/tracing_v3/utils.py +4 -4
- synth_ai/v0/api/__init__.py +8 -0
- synth_ai/v0/api/models/__init__.py +8 -0
- synth_ai/v0/api/models/supported.py +8 -0
- synth_ai/v0/config/__init__.py +15 -0
- synth_ai/v0/config/base_url.py +12 -0
- synth_ai/v0/lm/__init__.py +51 -0
- synth_ai/{lm → v0/lm}/caching/ephemeral.py +2 -2
- synth_ai/{lm → v0/lm}/caching/handler.py +4 -4
- synth_ai/{lm → v0/lm}/caching/initialize.py +1 -1
- synth_ai/{lm → v0/lm}/caching/persistent.py +1 -1
- synth_ai/{lm → v0/lm}/config.py +6 -1
- synth_ai/{lm → v0/lm}/core/all.py +9 -9
- synth_ai/{lm → v0/lm}/core/main.py +6 -6
- synth_ai/{lm → v0/lm}/core/main_v3.py +10 -10
- synth_ai/{lm → v0/lm}/core/synth_models.py +2 -14
- synth_ai/{lm → v0/lm}/core/vendor_clients.py +2 -2
- synth_ai/{lm → v0/lm}/overrides.py +2 -2
- synth_ai/{lm → v0/lm}/provider_support/anthropic.py +4 -4
- synth_ai/{lm → v0/lm}/provider_support/openai.py +5 -5
- synth_ai/{lm → v0/lm}/structured_outputs/handler.py +5 -5
- synth_ai/{lm → v0/lm}/structured_outputs/rehabilitate.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/core/anthropic_api.py +9 -9
- synth_ai/{lm → v0/lm}/vendors/core/gemini_api.py +5 -5
- synth_ai/{lm → v0/lm}/vendors/core/mistral_api.py +5 -5
- synth_ai/{lm → v0/lm}/vendors/core/openai_api.py +10 -10
- synth_ai/{lm → v0/lm}/vendors/openai_standard.py +8 -8
- synth_ai/{lm → v0/lm}/vendors/openai_standard_responses.py +2 -2
- synth_ai/{lm → v0/lm}/vendors/supported/custom_endpoint.py +3 -3
- synth_ai/{lm → v0/lm}/vendors/supported/deepseek.py +2 -2
- synth_ai/{lm → v0/lm}/vendors/supported/grok.py +2 -2
- synth_ai/{lm → v0/lm}/vendors/supported/groq.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/supported/ollama.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/supported/openrouter.py +3 -3
- synth_ai/{lm → v0/lm}/vendors/supported/together.py +1 -1
- synth_ai/{lm → v0/lm}/vendors/synth_client.py +1 -1
- synth_ai/v0/tracing_v3/__init__.py +10 -0
- synth_ai/v0/tracing_v3/abstractions.py +3 -0
- synth_ai/v0/tracing_v3/decorators.py +3 -0
- synth_ai/v0/tracing_v3/llm_call_record_helpers.py +3 -0
- synth_ai/v0/tracing_v3/session_tracer.py +3 -0
- synth_ai-0.2.9.dev8.dist-info/METADATA +191 -0
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/RECORD +268 -238
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/top_level.txt +1 -0
- examples/common_old/backend.py +0 -20
- examples/evals_old/README.md +0 -98
- examples/evals_old/__init__.py +0 -6
- examples/evals_old/compare_models.py +0 -1038
- examples/evals_old/example_log.md +0 -145
- examples/evals_old/run_demo.sh +0 -126
- examples/evals_old/trace_analysis.py +0 -270
- examples/finetuning_old/_backup_synth_qwen/config.toml +0 -29
- examples/finetuning_old/_backup_synth_qwen/example_log.md +0 -324
- examples/finetuning_old/_backup_synth_qwen/filter_traces.py +0 -60
- examples/finetuning_old/_backup_synth_qwen/filter_traces_achievements.py +0 -243
- examples/finetuning_old/_backup_synth_qwen/purge_v3_traces.py +0 -109
- examples/finetuning_old/_backup_synth_qwen/react_agent_lm.py +0 -1924
- examples/finetuning_old/_backup_synth_qwen/readme.md +0 -49
- examples/finetuning_old/_backup_synth_qwen/run_crafter_qwen4b.py +0 -114
- examples/finetuning_old/_backup_synth_qwen/run_demo.sh +0 -195
- examples/finetuning_old/_backup_synth_qwen/sft_kickoff.py +0 -119
- examples/finetuning_old/synth_qwen_v1/README.md +0 -68
- examples/finetuning_old/synth_qwen_v1/filter_traces.py +0 -60
- examples/finetuning_old/synth_qwen_v1/filter_traces_achievements.py +0 -243
- examples/finetuning_old/synth_qwen_v1/finetune.py +0 -46
- examples/finetuning_old/synth_qwen_v1/hello_ft_model.py +0 -71
- examples/finetuning_old/synth_qwen_v1/infer.py +0 -36
- examples/finetuning_old/synth_qwen_v1/poll.py +0 -46
- examples/finetuning_old/synth_qwen_v1/prepare_data.py +0 -35
- examples/finetuning_old/synth_qwen_v1/purge_v3_traces.py +0 -109
- examples/finetuning_old/synth_qwen_v1/react_agent_lm.py +0 -1933
- examples/finetuning_old/synth_qwen_v1/run_crafter_sft_job.py +0 -210
- examples/finetuning_old/synth_qwen_v1/run_ft_job.py +0 -237
- examples/finetuning_old/synth_qwen_v1/upload_data.py +0 -34
- examples/finetuning_old/synth_qwen_v1/util.py +0 -152
- examples/rl_old/task_app.py +0 -1131
- examples/warming_up_to_rl/old/event_rewards.md +0 -234
- examples/warming_up_to_rl/old/notes.md +0 -73
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -738
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
- synth_ai/experimental/synth_oss.py +0 -445
- synth_ai/learning/filtering.py +0 -0
- synth_ai/learning/offline/dpo.py +0 -0
- synth_ai/learning/offline/providers.py +0 -7
- synth_ai/learning/offline/sft.py +0 -0
- synth_ai/learning/offline/shared.py +0 -0
- synth_ai/learning/online/grpo.py +0 -0
- synth_ai/learning/online/irft.py +0 -0
- synth_ai/learning/prompts/banking77_injection_eval.py +0 -168
- synth_ai/learning/prompts/gepa.py +0 -0
- synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +0 -211
- synth_ai/learning/prompts/mipro.py +0 -289
- synth_ai/learning/prompts/random_search.py +0 -249
- synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
- synth_ai/learning/prompts/run_random_search_banking77.py +0 -329
- synth_ai/rl/secrets.py +0 -19
- synth_ai/scripts/verify_rewards.py +0 -100
- synth_ai/tracing/__init__.py +0 -30
- synth_ai/tracing_v1/__init__.py +0 -33
- synth_ai/tracing_v3/turso/__init__.py +0 -25
- synth_ai/tracing_v3/turso/manager.py +0 -838
- synth_ai/zyk/__init__.py +0 -30
- synth_ai-0.2.9.dev7.dist-info/METADATA +0 -131
- /synth_ai/{lm → v0/lm}/caching/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/caching/constants.py +0 -0
- /synth_ai/{lm → v0/lm}/caching/dbs.py +0 -0
- /synth_ai/{lm → v0/lm}/constants.py +0 -0
- /synth_ai/{lm → v0/lm}/core/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/core/exceptions.py +0 -0
- /synth_ai/{lm → v0/lm}/cost/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/cost/monitor.py +0 -0
- /synth_ai/{lm → v0/lm}/cost/statefulness.py +0 -0
- /synth_ai/{lm → v0/lm}/injection.py +0 -0
- /synth_ai/{lm → v0/lm}/provider_support/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/provider_support/suppress_logging.py +0 -0
- /synth_ai/{lm → v0/lm}/structured_outputs/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/structured_outputs/inject.py +0 -0
- /synth_ai/{lm → v0/lm}/tools/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/tools/base.py +0 -0
- /synth_ai/{lm → v0/lm}/unified_interface.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/base.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/core/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/core/synth_dev_api.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/local/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/local/ollama.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/retries.py +0 -0
- /synth_ai/{lm → v0/lm}/vendors/supported/__init__.py +0 -0
- /synth_ai/{lm → v0/lm}/warmup.py +0 -0
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
"""Main SessionTracer class for tracing v3."""
|
|
4
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import asyncio
|
|
6
|
+
import json
|
|
6
7
|
from contextlib import asynccontextmanager
|
|
7
|
-
from datetime import datetime
|
|
8
|
+
from datetime import UTC, datetime
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
10
11
|
from .abstractions import (
|
|
11
12
|
BaseEvent,
|
|
12
13
|
SessionEventMarkovBlanketMessage,
|
|
14
|
+
SessionMessageContent,
|
|
13
15
|
SessionTimeStep,
|
|
14
16
|
SessionTrace,
|
|
15
17
|
TimeRecord,
|
|
@@ -17,7 +19,9 @@ from .abstractions import (
|
|
|
17
19
|
from .config import CONFIG
|
|
18
20
|
from .decorators import set_session_id, set_session_tracer, set_turn_number
|
|
19
21
|
from .hooks import GLOBAL_HOOKS, HookManager
|
|
20
|
-
from .
|
|
22
|
+
from .storage.base import TraceStorage
|
|
23
|
+
from .storage.config import StorageConfig
|
|
24
|
+
from .storage.factory import create_storage
|
|
21
25
|
from .utils import generate_session_id
|
|
22
26
|
|
|
23
27
|
|
|
@@ -29,6 +33,8 @@ class SessionTracer:
|
|
|
29
33
|
hooks: HookManager | None = None,
|
|
30
34
|
db_url: str | None = None,
|
|
31
35
|
auto_save: bool = True,
|
|
36
|
+
storage: TraceStorage | None = None,
|
|
37
|
+
storage_config: StorageConfig | None = None,
|
|
32
38
|
):
|
|
33
39
|
"""Initialize session tracer.
|
|
34
40
|
|
|
@@ -41,7 +47,8 @@ class SessionTracer:
|
|
|
41
47
|
self._current_trace: SessionTrace | None = None
|
|
42
48
|
self._lock = asyncio.Lock()
|
|
43
49
|
self.db_url = db_url or CONFIG.db_url
|
|
44
|
-
self.
|
|
50
|
+
self._storage_config = storage_config
|
|
51
|
+
self.db: TraceStorage | None = storage
|
|
45
52
|
self.auto_save = auto_save
|
|
46
53
|
self._current_step: SessionTimeStep | None = None
|
|
47
54
|
|
|
@@ -58,7 +65,8 @@ class SessionTracer:
|
|
|
58
65
|
async def initialize(self):
|
|
59
66
|
"""Initialize the database connection."""
|
|
60
67
|
if self.db is None:
|
|
61
|
-
self.
|
|
68
|
+
config = self._storage_config or StorageConfig(connection_string=self.db_url)
|
|
69
|
+
self.db = create_storage(config)
|
|
62
70
|
await self.db.initialize()
|
|
63
71
|
|
|
64
72
|
async def start_session(
|
|
@@ -98,7 +106,7 @@ class SessionTracer:
|
|
|
98
106
|
|
|
99
107
|
self._current_trace = SessionTrace(
|
|
100
108
|
session_id=session_id,
|
|
101
|
-
created_at=datetime.
|
|
109
|
+
created_at=datetime.now(UTC),
|
|
102
110
|
session_time_steps=[],
|
|
103
111
|
event_history=[],
|
|
104
112
|
markov_blanket_message_history=[],
|
|
@@ -144,7 +152,7 @@ class SessionTracer:
|
|
|
144
152
|
step = SessionTimeStep(
|
|
145
153
|
step_id=step_id,
|
|
146
154
|
step_index=len(self._current_trace.session_time_steps),
|
|
147
|
-
timestamp=datetime.
|
|
155
|
+
timestamp=datetime.now(UTC),
|
|
148
156
|
turn_number=turn_number,
|
|
149
157
|
step_metadata=metadata or {},
|
|
150
158
|
)
|
|
@@ -189,7 +197,7 @@ class SessionTracer:
|
|
|
189
197
|
step = self._current_step
|
|
190
198
|
|
|
191
199
|
if step and step.completed_at is None:
|
|
192
|
-
step.completed_at = datetime.
|
|
200
|
+
step.completed_at = datetime.now(UTC)
|
|
193
201
|
|
|
194
202
|
# Trigger hooks
|
|
195
203
|
await self.hooks.trigger(
|
|
@@ -262,7 +270,7 @@ class SessionTracer:
|
|
|
262
270
|
|
|
263
271
|
async def record_message(
|
|
264
272
|
self,
|
|
265
|
-
content:
|
|
273
|
+
content: Any,
|
|
266
274
|
message_type: str,
|
|
267
275
|
event_time: float | None = None,
|
|
268
276
|
message_time: int | None = None,
|
|
@@ -280,11 +288,13 @@ class SessionTracer:
|
|
|
280
288
|
if self._current_trace is None:
|
|
281
289
|
raise RuntimeError("No active session")
|
|
282
290
|
|
|
291
|
+
normalised_content, content_str = self._normalise_message_content(content)
|
|
292
|
+
|
|
283
293
|
msg = SessionEventMarkovBlanketMessage(
|
|
284
|
-
content=
|
|
294
|
+
content=normalised_content,
|
|
285
295
|
message_type=message_type,
|
|
286
296
|
time_record=TimeRecord(
|
|
287
|
-
event_time=event_time or datetime.
|
|
297
|
+
event_time=event_time or datetime.now(UTC).timestamp(), message_time=message_time
|
|
288
298
|
),
|
|
289
299
|
metadata=metadata or {},
|
|
290
300
|
)
|
|
@@ -318,7 +328,7 @@ class SessionTracer:
|
|
|
318
328
|
self._current_trace.session_id,
|
|
319
329
|
timestep_db_id=timestep_db_id,
|
|
320
330
|
message_type=message_type,
|
|
321
|
-
content=
|
|
331
|
+
content=content_str,
|
|
322
332
|
event_time=msg.time_record.event_time,
|
|
323
333
|
message_time=msg.time_record.message_time,
|
|
324
334
|
metadata=msg.metadata,
|
|
@@ -326,6 +336,22 @@ class SessionTracer:
|
|
|
326
336
|
return message_id
|
|
327
337
|
return None
|
|
328
338
|
|
|
339
|
+
@staticmethod
|
|
340
|
+
def _normalise_message_content(content: Any) -> tuple[SessionMessageContent, str]:
|
|
341
|
+
if isinstance(content, SessionMessageContent):
|
|
342
|
+
return content, content.as_text()
|
|
343
|
+
if isinstance(content, str):
|
|
344
|
+
payload = SessionMessageContent(text=content)
|
|
345
|
+
return payload, payload.as_text()
|
|
346
|
+
try:
|
|
347
|
+
serialized = json.dumps(content, ensure_ascii=False)
|
|
348
|
+
payload = SessionMessageContent(json_payload=serialized)
|
|
349
|
+
return payload, serialized
|
|
350
|
+
except (TypeError, ValueError):
|
|
351
|
+
text = str(content)
|
|
352
|
+
payload = SessionMessageContent(text=text)
|
|
353
|
+
return payload, text
|
|
354
|
+
|
|
329
355
|
async def end_session(self, save: bool | None = None) -> SessionTrace:
|
|
330
356
|
"""End the current session.
|
|
331
357
|
|
|
@@ -342,7 +368,7 @@ class SessionTracer:
|
|
|
342
368
|
# End any open timesteps
|
|
343
369
|
for step in self._current_trace.session_time_steps:
|
|
344
370
|
if step.completed_at is None:
|
|
345
|
-
step.completed_at = datetime.
|
|
371
|
+
step.completed_at = datetime.now(UTC)
|
|
346
372
|
|
|
347
373
|
# Trigger pre-save hooks
|
|
348
374
|
await self.hooks.trigger("before_save", session=self._current_trace)
|
|
@@ -88,6 +88,91 @@ class TraceStorage(ABC):
|
|
|
88
88
|
"""Close the storage connection."""
|
|
89
89
|
pass
|
|
90
90
|
|
|
91
|
+
# Incremental helpers -------------------------------------------------
|
|
92
|
+
|
|
93
|
+
@abstractmethod
|
|
94
|
+
async def ensure_session(
|
|
95
|
+
self,
|
|
96
|
+
session_id: str,
|
|
97
|
+
*,
|
|
98
|
+
created_at: datetime | None = None,
|
|
99
|
+
metadata: dict[str, Any] | None = None,
|
|
100
|
+
) -> None:
|
|
101
|
+
"""Ensure a session row exists for the given session id."""
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
async def ensure_timestep(
|
|
106
|
+
self,
|
|
107
|
+
session_id: str,
|
|
108
|
+
*,
|
|
109
|
+
step_id: str,
|
|
110
|
+
step_index: int,
|
|
111
|
+
turn_number: int | None = None,
|
|
112
|
+
started_at: datetime | None = None,
|
|
113
|
+
completed_at: datetime | None = None,
|
|
114
|
+
metadata: dict[str, Any] | None = None,
|
|
115
|
+
) -> int:
|
|
116
|
+
"""Ensure a timestep row exists and return its database id."""
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
@abstractmethod
|
|
120
|
+
async def insert_event_row(
|
|
121
|
+
self,
|
|
122
|
+
session_id: str,
|
|
123
|
+
*,
|
|
124
|
+
timestep_db_id: int | None,
|
|
125
|
+
event: Any,
|
|
126
|
+
metadata_override: dict[str, Any] | None = None,
|
|
127
|
+
) -> int:
|
|
128
|
+
"""Insert an event and return its database id."""
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
@abstractmethod
|
|
132
|
+
async def insert_message_row(
|
|
133
|
+
self,
|
|
134
|
+
session_id: str,
|
|
135
|
+
*,
|
|
136
|
+
timestep_db_id: int | None,
|
|
137
|
+
message_type: str,
|
|
138
|
+
content: Any,
|
|
139
|
+
event_time: float | None = None,
|
|
140
|
+
message_time: int | None = None,
|
|
141
|
+
metadata: dict[str, Any] | None = None,
|
|
142
|
+
) -> int:
|
|
143
|
+
"""Insert a message row linked to a session/timestep."""
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
@abstractmethod
|
|
147
|
+
async def insert_outcome_reward(
|
|
148
|
+
self,
|
|
149
|
+
session_id: str,
|
|
150
|
+
*,
|
|
151
|
+
total_reward: int,
|
|
152
|
+
achievements_count: int,
|
|
153
|
+
total_steps: int,
|
|
154
|
+
reward_metadata: dict | None = None,
|
|
155
|
+
) -> int:
|
|
156
|
+
"""Record an outcome reward for a session."""
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
@abstractmethod
|
|
160
|
+
async def insert_event_reward(
|
|
161
|
+
self,
|
|
162
|
+
session_id: str,
|
|
163
|
+
*,
|
|
164
|
+
event_id: int,
|
|
165
|
+
message_id: int | None = None,
|
|
166
|
+
turn_number: int | None = None,
|
|
167
|
+
reward_value: float = 0.0,
|
|
168
|
+
reward_type: str | None = None,
|
|
169
|
+
key: str | None = None,
|
|
170
|
+
annotation: dict[str, Any] | None = None,
|
|
171
|
+
source: str | None = None,
|
|
172
|
+
) -> int:
|
|
173
|
+
"""Record a reward tied to a specific event."""
|
|
174
|
+
pass
|
|
175
|
+
|
|
91
176
|
# Optional experiment management methods
|
|
92
177
|
async def create_experiment(
|
|
93
178
|
self,
|
|
@@ -9,16 +9,22 @@ from typing import Any
|
|
|
9
9
|
class StorageBackend(str, Enum):
|
|
10
10
|
"""Supported storage backends."""
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
TURSO_NATIVE = "turso_native"
|
|
13
13
|
SQLITE = "sqlite"
|
|
14
14
|
POSTGRES = "postgres" # Future support
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
def _is_enabled(value: str | None) -> bool:
|
|
18
|
+
if value is None:
|
|
19
|
+
return False
|
|
20
|
+
return value.lower() in {"1", "true", "yes", "on"}
|
|
21
|
+
|
|
22
|
+
|
|
17
23
|
@dataclass
|
|
18
24
|
class StorageConfig:
|
|
19
25
|
"""Configuration for storage backend."""
|
|
20
26
|
|
|
21
|
-
backend: StorageBackend = StorageBackend.
|
|
27
|
+
backend: StorageBackend = StorageBackend.TURSO_NATIVE
|
|
22
28
|
connection_string: str | None = None
|
|
23
29
|
|
|
24
30
|
# Turso-specific settings
|
|
@@ -34,23 +40,30 @@ class StorageConfig:
|
|
|
34
40
|
enable_compression: bool = os.getenv("STORAGE_COMPRESSION", "false").lower() == "true"
|
|
35
41
|
max_content_length: int = int(os.getenv("STORAGE_MAX_CONTENT_LENGTH", "1000000")) # 1MB
|
|
36
42
|
|
|
43
|
+
def __post_init__(self):
|
|
44
|
+
# Allow legacy override while keeping compatibility with existing TURSO_NATIVE env flag
|
|
45
|
+
native_env = os.getenv("TURSO_NATIVE")
|
|
46
|
+
native_flag = _is_enabled(native_env) if native_env is not None else None
|
|
47
|
+
|
|
48
|
+
if native_flag is False:
|
|
49
|
+
self.backend = StorageBackend.SQLITE
|
|
50
|
+
|
|
37
51
|
def get_connection_string(self) -> str:
|
|
38
52
|
"""Get the appropriate connection string for the backend."""
|
|
39
53
|
if self.connection_string:
|
|
40
54
|
return self.connection_string
|
|
41
55
|
|
|
42
|
-
if self.backend == StorageBackend.
|
|
56
|
+
if self.backend == StorageBackend.TURSO_NATIVE:
|
|
43
57
|
return self.turso_url
|
|
44
|
-
|
|
58
|
+
if self.backend == StorageBackend.SQLITE:
|
|
45
59
|
return "sqlite+aiosqlite:///traces.db"
|
|
46
|
-
|
|
60
|
+
if self.backend == StorageBackend.POSTGRES:
|
|
47
61
|
return os.getenv("POSTGRES_URL", "postgresql+asyncpg://localhost/traces")
|
|
48
|
-
|
|
49
|
-
raise ValueError(f"Unknown backend: {self.backend}")
|
|
62
|
+
raise ValueError(f"Unknown backend: {self.backend}")
|
|
50
63
|
|
|
51
64
|
def get_backend_config(self) -> dict[str, Any]:
|
|
52
65
|
"""Get backend-specific configuration."""
|
|
53
|
-
if self.backend == StorageBackend.
|
|
66
|
+
if self.backend == StorageBackend.TURSO_NATIVE:
|
|
54
67
|
config = {}
|
|
55
68
|
if self.turso_auth_token:
|
|
56
69
|
config["auth_token"] = self.turso_auth_token
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Factory for creating storage instances."""
|
|
2
2
|
|
|
3
|
-
from ..turso.
|
|
3
|
+
from ..turso.native_manager import NativeLibsqlTraceManager
|
|
4
4
|
from .base import TraceStorage
|
|
5
5
|
from .config import StorageBackend, StorageConfig
|
|
6
6
|
|
|
@@ -22,13 +22,16 @@ def create_storage(config: StorageConfig | None = None) -> TraceStorage:
|
|
|
22
22
|
|
|
23
23
|
config = STORAGE_CONFIG
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
connection_string = config.get_connection_string()
|
|
26
|
+
|
|
27
|
+
if config.backend == StorageBackend.TURSO_NATIVE:
|
|
28
|
+
backend_config = config.get_backend_config()
|
|
29
|
+
return NativeLibsqlTraceManager(
|
|
30
|
+
db_url=connection_string,
|
|
31
|
+
auth_token=backend_config.get("auth_token"),
|
|
32
|
+
)
|
|
28
33
|
elif config.backend == StorageBackend.SQLITE:
|
|
29
|
-
|
|
30
|
-
# but with a file-based URL
|
|
31
|
-
return AsyncSQLTraceManager(db_url=config.get_connection_string())
|
|
34
|
+
return NativeLibsqlTraceManager(db_url=connection_string)
|
|
32
35
|
elif config.backend == StorageBackend.POSTGRES:
|
|
33
36
|
# Future: PostgreSQL implementation
|
|
34
37
|
raise NotImplementedError("PostgreSQL backend not yet implemented")
|
|
@@ -21,7 +21,7 @@ def retry_async(max_attempts: int = 3, delay: float = 1.0, backoff: float = 2.0)
|
|
|
21
21
|
def decorator(func: Callable[..., T]) -> Callable[..., T]:
|
|
22
22
|
@functools.wraps(func)
|
|
23
23
|
async def wrapper(*args, **kwargs):
|
|
24
|
-
last_exception = None
|
|
24
|
+
last_exception: Exception | None = None
|
|
25
25
|
current_delay = delay
|
|
26
26
|
|
|
27
27
|
for attempt in range(max_attempts):
|
|
@@ -35,7 +35,9 @@ def retry_async(max_attempts: int = 3, delay: float = 1.0, backoff: float = 2.0)
|
|
|
35
35
|
else:
|
|
36
36
|
raise
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
if last_exception:
|
|
39
|
+
raise last_exception
|
|
40
|
+
raise RuntimeError("Retry logic failed without exception")
|
|
39
41
|
|
|
40
42
|
return wrapper
|
|
41
43
|
|
|
@@ -13,7 +13,12 @@ from ..config import CONFIG
|
|
|
13
13
|
class SqldDaemon:
|
|
14
14
|
"""Manages local sqld daemon lifecycle."""
|
|
15
15
|
|
|
16
|
-
def __init__(
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
db_path: str | None = None,
|
|
19
|
+
http_port: int | None = None,
|
|
20
|
+
binary_path: str | None = None,
|
|
21
|
+
):
|
|
17
22
|
"""Initialize sqld daemon manager.
|
|
18
23
|
|
|
19
24
|
Args:
|
|
@@ -120,7 +125,7 @@ class SqldDaemon:
|
|
|
120
125
|
_daemon: SqldDaemon | None = None
|
|
121
126
|
|
|
122
127
|
|
|
123
|
-
def start_sqld(db_path: str = None, port: int = None) -> SqldDaemon:
|
|
128
|
+
def start_sqld(db_path: str | None = None, port: int | None = None) -> SqldDaemon:
|
|
124
129
|
"""Start a global sqld daemon instance."""
|
|
125
130
|
global _daemon
|
|
126
131
|
if _daemon and _daemon.is_running():
|