synth-ai 0.22.2.dev688__tar.gz → 0.22.2.dev690__tar.gz
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-0.22.2.dev688/synth_ai.egg-info → synth_ai-0.22.2.dev690}/PKG-INFO +1 -1
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/pyproject.toml +1 -1
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/http/async_transport.py +3 -2
- synth_ai-0.22.2.dev690/synth_ai/core/http/retry.py +302 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/http/transport.py +85 -15
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/__init__.py +2 -0
- synth_ai-0.22.2.dev690/synth_ai/sdk/research/__init__.py +69 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/advanced_swarms.py +19 -6
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/client.py +56 -1
- synth_ai-0.22.2.dev690/synth_ai/sdk/research/execution_reads.py +260 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/facade.py +13 -0
- synth_ai-0.22.2.dev690/synth_ai/sdk/research/hierarchy.py +552 -0
- synth_ai-0.22.2.dev690/synth_ai/sdk/research/hierarchy_models.py +474 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/operations.py +78 -0
- synth_ai-0.22.2.dev690/synth_ai/sdk/research/owner_reads.py +341 -0
- synth_ai-0.22.2.dev690/synth_ai/sdk/research/planning_reads.py +331 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/projects.py +4 -1
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/client.py +31 -9
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/swarms.py +5 -1
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690/synth_ai.egg-info}/PKG-INFO +1 -1
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai.egg-info/SOURCES.txt +5 -0
- synth_ai-0.22.2.dev688/synth_ai/core/http/retry.py +0 -135
- synth_ai-0.22.2.dev688/synth_ai/sdk/research/__init__.py +0 -26
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/LICENSE +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/MANIFEST.in +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/openapi/index-v1.json +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/openapi/messaging-v1.json +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/openapi/research-v1.json +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/setup.cfg +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/setup.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/__main__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/AGENTS.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/__main__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/index.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/main.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/research.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/research_environments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/research_image_releases.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/research_projects.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/utils/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/cli/utils/research_launch.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/client.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/auth/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/auth/credentials.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/contracts/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/contracts/json_value.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/contracts/pagination.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/errors.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/http/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/http/request.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/http/streaming.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/local_files.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/research/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/utils/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/utils/env.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/utils/log_filter.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/utils/paths.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/core/utils/urls.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/__main__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/objective_tools.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/registry.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/request_models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/server.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/approvals.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/artifacts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/datasets.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/environments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/exports.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/factories.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/factory_results.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/files.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/image_releases.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/index.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/index_qa.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/integrations.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/intern_program.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/launch_schemas.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/local_files.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/logs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/outputs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/policy_schemas.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/progress.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/project_data.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/projects.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/prs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/readiness.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/repos.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/research_intern.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/resource_reads.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/resources.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/runs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/scientific_records.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/trained_models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/usage.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/visuals.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/mcp/research/tools/workspace_inputs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/pools.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/py.typed +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/AGENT_SETUP_PROMPT.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/agent_policy.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/artifacts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/catalog.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/catalogue.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/classification.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/client.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/contracts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/contributions.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/errors.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/forge_notices.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/intake.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/lifecycle.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/local_files.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/manifest.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/oauth.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/package.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/public.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/public_corpus.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/public_search.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/qa.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/qa_checks.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/qa_preflight.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/qa_reviews.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/research/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/research/build.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/research/capture.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/research/contracts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/research/files.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/research/release.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/research_intake.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/retry.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/rights.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/scientific_provenance.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/scope_errors.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/scopes.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/search.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/submission.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/timeouts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/transfer.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/upload_session.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/usage_accounting.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/value.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/index/wallet_search.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/messaging/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/messaging/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/messaging/client.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/messaging/contracts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/optimizers/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/optimizers/client.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/optimizers/contracts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/pagination.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/_internal/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/_internal/crypto.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/_internal/env.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/_internal/urls.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/account.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/advanced.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/advanced_factories.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/artifacts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/auth.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/container_pools/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/container_pools/api.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/container_pools/contracts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/container_pools/operations.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/container_pools/packaging.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/_activity_wire.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/_environment_wire.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/_transcript_wire.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/_wire.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/activity.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/activity_items.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/actor_images.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/billing.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/canonical_usage.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/checkpoints.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/cloud_deployment_claims.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/cloud_deployments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/common.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/dataset_revisions.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/deliveries.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/dev_environment_evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/economics.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/environment_manifest.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/environments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/experiment_evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/factories.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/factory_evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/factory_lenses.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/factory_operations.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/factory_role_receipts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/failure.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/contracts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/evaluation.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/exports.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/operations.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/records.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/resources.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge/schema.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge_citations.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/forge_uploads.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/image_releases.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/intern_authority.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/intern_blockers.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/intern_grants.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/intern_program.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/intern_resources.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/intern_usage.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/limit_evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/local_execution_profile.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/native_attachment.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/native_result_outcome.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/operator_evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/project.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/project_data.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/project_runtime.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/project_workspace.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/project_workspace_evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/projects.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/promotions.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/research_intern.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/resource_reads.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/resource_settlement.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_authority.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_control.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_diagnostics.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_events.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_execution.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_launch.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_observability.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_state.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/run_timeline.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/runtime_image.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/runtime_intent.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/runtime_stream.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/runtime_stream_snapshot.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/scientific_citations.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/scientific_integrity.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_actor_models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_actor_policy_data.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_agent_harnesses.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_agent_kinds.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_agent_models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_branching.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_credential_providers.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_environment_kinds.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_evidence_obligations.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_funding_sources.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_horizons.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_host_kinds.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_inference_providers.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_network_topology.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_providers.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_resource_kinds.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_roles.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_run_policy.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_runbooks.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_runnable_project.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_runtime_kinds.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_tool_providers.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/smr_work_modes.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/status.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/swarm_controls.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/swarm_history.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/swarm_rollouts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/swarm_tasks.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/swarms.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/tag.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/traces.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/transcript.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/types.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/usage.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/visuals.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/wire_models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/wire_models_README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/work_products.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/contracts/workspaces.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/economics.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/efforts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/environments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/errors.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/events.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/experiments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/factories.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/factory_storage.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/image_releases.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/intern_authority.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/intern_blockers.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/intern_program.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/knowledge.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/project_data.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/project_deliveries.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/project_workspaces.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/public.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/readouts.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/research_intern.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/resource_reads.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/scientific_records.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/secrets.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/README.md +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/_base.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/_client_helpers.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/_run_authority_mixin.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/approvals.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/billing.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/cloud_deployments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/config.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/cost.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/datasets.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/dev_environments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/directory_inputs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/environments.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/exports.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/factories.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/factory_evidence.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/files.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/github.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/image_releases.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/images.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/logs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/outputs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/progress.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/project.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/projects.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/prs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/readiness.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/repositories.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/runs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/secrets.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/setup.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/tag.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/trained_models.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/transport.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/usage.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/work_products.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/session/workspace_inputs.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/surface_parity.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/traces.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/transport/__init__.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/transport/http.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/transport/pagination.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/version.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/visuals.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai/sdk/research/wiki.py +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai.egg-info/dependency_links.txt +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai.egg-info/entry_points.txt +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai.egg-info/requires.txt +0 -0
- {synth_ai-0.22.2.dev688 → synth_ai-0.22.2.dev690}/synth_ai.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "synth-ai"
|
|
3
|
-
version = "0.22.2.
|
|
3
|
+
version = "0.22.2.dev690"
|
|
4
4
|
description = "Python SDK, CLI and MCP servers for Synth Index search and Swarms"
|
|
5
5
|
keywords = ["synth", "index", "search", "citations", "research", "swarms", "mcp", "sdk"]
|
|
6
6
|
authors = [{name = "Synth AI", email = "josh@usesynth.ai"}]
|
|
@@ -38,12 +38,13 @@ class AsyncHttpTransport:
|
|
|
38
38
|
"""One native async transport for JSON, bytes, and SSE operations."""
|
|
39
39
|
|
|
40
40
|
base_url: str
|
|
41
|
-
headers: Mapping[str, str]
|
|
41
|
+
headers: Mapping[str, str] = field(repr=False)
|
|
42
42
|
timeout_seconds: float = 30.0
|
|
43
43
|
retry_policy: RetryPolicy = field(default_factory=RetryPolicy)
|
|
44
44
|
error_handler: ErrorHandler = raise_http_error
|
|
45
45
|
exception_handler: ExceptionHandler = raise_transport_exception
|
|
46
46
|
decode_error_handler: DecodeErrorHandler = raise_json_decode_error
|
|
47
|
+
follow_redirects: bool = True
|
|
47
48
|
client: httpx.AsyncClient = field(init=False, repr=False)
|
|
48
49
|
|
|
49
50
|
def __post_init__(self) -> None:
|
|
@@ -52,7 +53,7 @@ class AsyncHttpTransport:
|
|
|
52
53
|
headers=dict(self.headers),
|
|
53
54
|
timeout=self.timeout_seconds,
|
|
54
55
|
limits=httpx.Limits(max_keepalive_connections=0),
|
|
55
|
-
follow_redirects=
|
|
56
|
+
follow_redirects=self.follow_redirects,
|
|
56
57
|
)
|
|
57
58
|
|
|
58
59
|
async def close(self) -> None:
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Classified retry policy shared by sync and async transports.
|
|
2
|
+
|
|
3
|
+
# See: testing/specifications/sdk/core_research_migration.md
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
import random
|
|
10
|
+
from collections.abc import Mapping
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
|
|
13
|
+
from synth_ai.core.errors import (
|
|
14
|
+
ContractMismatchError,
|
|
15
|
+
RetryDirective,
|
|
16
|
+
RuntimeUnavailableError,
|
|
17
|
+
SynthError,
|
|
18
|
+
SynthErrorCategory,
|
|
19
|
+
SynthErrorCode,
|
|
20
|
+
SynthFailure,
|
|
21
|
+
)
|
|
22
|
+
from synth_ai.core.http.request import HttpMethod, HttpRequest, OperationMetadata
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True, slots=True)
|
|
26
|
+
class RetryPolicy:
|
|
27
|
+
attempts_max: int = 3
|
|
28
|
+
delay_seconds_initial: float = 0.5
|
|
29
|
+
delay_seconds_max: float = 5.0
|
|
30
|
+
retry_statuses: frozenset[int] = frozenset({408, 409, 429, 500, 502, 503, 504})
|
|
31
|
+
|
|
32
|
+
def __post_init__(self) -> None:
|
|
33
|
+
if (
|
|
34
|
+
isinstance(self.attempts_max, bool)
|
|
35
|
+
or not isinstance(self.attempts_max, int)
|
|
36
|
+
or not 1 <= self.attempts_max <= 100
|
|
37
|
+
):
|
|
38
|
+
raise ValueError("attempts_max must be an integer from 1 through 100")
|
|
39
|
+
for delay in (self.delay_seconds_initial, self.delay_seconds_max):
|
|
40
|
+
if (
|
|
41
|
+
isinstance(delay, bool)
|
|
42
|
+
or not isinstance(delay, (int, float))
|
|
43
|
+
or not math.isfinite(delay)
|
|
44
|
+
):
|
|
45
|
+
raise ValueError("retry delays must be finite numbers")
|
|
46
|
+
if self.delay_seconds_initial < 0 or self.delay_seconds_max < 0:
|
|
47
|
+
raise ValueError("retry delays must be non-negative")
|
|
48
|
+
if self.delay_seconds_initial > self.delay_seconds_max:
|
|
49
|
+
raise ValueError("delay_seconds_initial cannot exceed delay_seconds_max")
|
|
50
|
+
|
|
51
|
+
def permits(
|
|
52
|
+
self,
|
|
53
|
+
operation: OperationMetadata,
|
|
54
|
+
*,
|
|
55
|
+
idempotency_key: str | None,
|
|
56
|
+
) -> bool:
|
|
57
|
+
"""Retry only metadata-declared idempotent operations.
|
|
58
|
+
|
|
59
|
+
Unsafe methods additionally require an idempotency key.
|
|
60
|
+
"""
|
|
61
|
+
if not operation.idempotent:
|
|
62
|
+
return False
|
|
63
|
+
if operation.method is HttpMethod.GET:
|
|
64
|
+
return True
|
|
65
|
+
return bool(idempotency_key)
|
|
66
|
+
|
|
67
|
+
def delay_seconds(
|
|
68
|
+
self,
|
|
69
|
+
attempt_index: int,
|
|
70
|
+
*,
|
|
71
|
+
retry_after_seconds: float | None,
|
|
72
|
+
) -> float:
|
|
73
|
+
"""Deterministic exponential backoff capped by policy and Retry-After."""
|
|
74
|
+
if attempt_index < 0:
|
|
75
|
+
raise ValueError("attempt_index must be non-negative")
|
|
76
|
+
exponential = min(
|
|
77
|
+
self.delay_seconds_max,
|
|
78
|
+
self.delay_seconds_initial * (2**attempt_index),
|
|
79
|
+
)
|
|
80
|
+
if retry_after_seconds is None:
|
|
81
|
+
return exponential
|
|
82
|
+
if not math.isfinite(retry_after_seconds) or retry_after_seconds < 0:
|
|
83
|
+
raise ValueError("retry_after_seconds must be non-negative")
|
|
84
|
+
return min(self.delay_seconds_max, max(exponential, retry_after_seconds))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def idempotency_key_from_request(request: HttpRequest) -> str | None:
|
|
88
|
+
"""Extract an idempotency key from headers or JSON body fields."""
|
|
89
|
+
values = [value for name, value in request.headers.items() if name.lower() == "idempotency-key"]
|
|
90
|
+
if isinstance(request.body, dict):
|
|
91
|
+
values.extend(
|
|
92
|
+
request.body[name]
|
|
93
|
+
for name in ("idempotency_key", "idempotency_key_run_create")
|
|
94
|
+
if name in request.body
|
|
95
|
+
)
|
|
96
|
+
identities = set()
|
|
97
|
+
for value in values:
|
|
98
|
+
if not isinstance(value, str) or not value.strip():
|
|
99
|
+
raise ValueError("idempotency identity must be a non-empty string")
|
|
100
|
+
identities.add(value)
|
|
101
|
+
if len(identities) > 1:
|
|
102
|
+
raise ValueError("request contains conflicting idempotency identities")
|
|
103
|
+
return next(iter(identities), None)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def should_retry_failure(
|
|
107
|
+
policy: RetryPolicy,
|
|
108
|
+
request: HttpRequest,
|
|
109
|
+
error: BaseException,
|
|
110
|
+
) -> bool:
|
|
111
|
+
"""Decide whether one failed execute attempt may be retried."""
|
|
112
|
+
if isinstance(error, (ContractMismatchError, RuntimeUnavailableError)):
|
|
113
|
+
return False
|
|
114
|
+
if not policy.permits(
|
|
115
|
+
request.operation,
|
|
116
|
+
idempotency_key=idempotency_key_from_request(request),
|
|
117
|
+
):
|
|
118
|
+
return False
|
|
119
|
+
if isinstance(error, SynthError):
|
|
120
|
+
if error.failure is not None:
|
|
121
|
+
# The first-class directive is authoritative, including an explicit false.
|
|
122
|
+
return error.failure.retry.retryable
|
|
123
|
+
if error.retryable:
|
|
124
|
+
return True
|
|
125
|
+
status = None
|
|
126
|
+
if error.failure is not None:
|
|
127
|
+
status = error.failure.status
|
|
128
|
+
if status is None and hasattr(error, "status"):
|
|
129
|
+
status = error.status
|
|
130
|
+
return isinstance(status, int) and status in policy.retry_statuses
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def retry_after_from_error(error: BaseException) -> float | None:
|
|
135
|
+
if isinstance(error, SynthError):
|
|
136
|
+
return error.retry_after_seconds
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# Backend ``core/data/db/backpressure_classification.py::DB_BACKPRESSURE_REASON_CODE``,
|
|
141
|
+
# emitted as ``error_code`` by ``core/data/db/admission.py::db_backpressure_payload``.
|
|
142
|
+
DB_BACKPRESSURE_ERROR_CODE = "db_backpressure"
|
|
143
|
+
DB_BACKPRESSURE_RETRY_EXHAUSTED_CODE = "db_backpressure_retry_exhausted"
|
|
144
|
+
_REPLAY_SAFE_METHODS = frozenset({"GET", "HEAD", "OPTIONS"})
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@dataclass(frozen=True, slots=True)
|
|
148
|
+
class DbBackpressureRefusal:
|
|
149
|
+
"""One typed DB backpressure refusal decoded from a backend error body."""
|
|
150
|
+
|
|
151
|
+
status: int
|
|
152
|
+
error_code: str
|
|
153
|
+
component: str | None
|
|
154
|
+
work_class: str | None
|
|
155
|
+
retry_after_seconds: float | None
|
|
156
|
+
operator_action: str | None
|
|
157
|
+
message: str
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@dataclass(frozen=True, slots=True)
|
|
161
|
+
class DbBackpressureRetryPolicy:
|
|
162
|
+
"""Bounds for replaying a request the backend shed before starting DB work.
|
|
163
|
+
|
|
164
|
+
Attempts and total sleep are both bounded; the server's ``retry_after`` is
|
|
165
|
+
honored up to ``retry_after_cap_seconds`` and only ever lengthened by jitter.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
attempts_max: int = 5
|
|
169
|
+
total_wait_seconds_max: float = 120.0
|
|
170
|
+
retry_after_cap_seconds: float = 30.0
|
|
171
|
+
delay_seconds_initial: float = 1.0
|
|
172
|
+
jitter_ratio: float = 0.25
|
|
173
|
+
|
|
174
|
+
def __post_init__(self) -> None:
|
|
175
|
+
if (
|
|
176
|
+
isinstance(self.attempts_max, bool)
|
|
177
|
+
or not isinstance(self.attempts_max, int)
|
|
178
|
+
or not 1 <= self.attempts_max <= 20
|
|
179
|
+
):
|
|
180
|
+
raise ValueError("attempts_max must be an integer from 1 through 20")
|
|
181
|
+
for name in (
|
|
182
|
+
"total_wait_seconds_max",
|
|
183
|
+
"retry_after_cap_seconds",
|
|
184
|
+
"delay_seconds_initial",
|
|
185
|
+
"jitter_ratio",
|
|
186
|
+
):
|
|
187
|
+
value = getattr(self, name)
|
|
188
|
+
if (
|
|
189
|
+
isinstance(value, bool)
|
|
190
|
+
or not isinstance(value, (int, float))
|
|
191
|
+
or not math.isfinite(value)
|
|
192
|
+
or value < 0
|
|
193
|
+
):
|
|
194
|
+
raise ValueError(f"{name} must be a finite non-negative number")
|
|
195
|
+
if self.jitter_ratio > 1:
|
|
196
|
+
raise ValueError("jitter_ratio cannot exceed 1")
|
|
197
|
+
|
|
198
|
+
def next_delay_seconds(
|
|
199
|
+
self,
|
|
200
|
+
*,
|
|
201
|
+
attempts_made: int,
|
|
202
|
+
waited_seconds: float,
|
|
203
|
+
refusal: DbBackpressureRefusal,
|
|
204
|
+
rng: random.Random,
|
|
205
|
+
) -> float | None:
|
|
206
|
+
"""Return the sleep before the next attempt, or None when bounds are spent."""
|
|
207
|
+
if attempts_made >= self.attempts_max:
|
|
208
|
+
return None
|
|
209
|
+
if refusal.retry_after_seconds is not None:
|
|
210
|
+
base = min(self.retry_after_cap_seconds, refusal.retry_after_seconds)
|
|
211
|
+
else:
|
|
212
|
+
base = min(
|
|
213
|
+
self.retry_after_cap_seconds,
|
|
214
|
+
self.delay_seconds_initial * (2 ** (attempts_made - 1)),
|
|
215
|
+
)
|
|
216
|
+
delay = base * (1.0 + rng.uniform(0.0, self.jitter_ratio))
|
|
217
|
+
if waited_seconds + delay > self.total_wait_seconds_max:
|
|
218
|
+
return None
|
|
219
|
+
return delay
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def request_permits_replay(method: str, headers: Mapping[str, str]) -> bool:
|
|
223
|
+
"""A request may be replayed only when safe by method or carrying an idempotency key."""
|
|
224
|
+
if method.upper() in _REPLAY_SAFE_METHODS:
|
|
225
|
+
return True
|
|
226
|
+
return any(
|
|
227
|
+
name.lower() == "idempotency-key" and bool(str(value).strip())
|
|
228
|
+
for name, value in headers.items()
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class DbBackpressureRetryExhaustedError(SynthError):
|
|
233
|
+
"""The backend kept shedding DB work past the retry bounds.
|
|
234
|
+
|
|
235
|
+
Carries the last refusal's ``component``, ``work_class`` and ``retry_after``.
|
|
236
|
+
Not retryable again: callers already spent the bounded budget.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
def __init__(
|
|
240
|
+
self,
|
|
241
|
+
*,
|
|
242
|
+
method: str,
|
|
243
|
+
path: str,
|
|
244
|
+
operation_id: str | None,
|
|
245
|
+
refusal: DbBackpressureRefusal,
|
|
246
|
+
attempts: int,
|
|
247
|
+
waited_seconds: float,
|
|
248
|
+
) -> None:
|
|
249
|
+
self.method = method
|
|
250
|
+
self.path = path
|
|
251
|
+
self.refusal = refusal
|
|
252
|
+
self.attempts = attempts
|
|
253
|
+
self.waited_seconds = waited_seconds
|
|
254
|
+
detail = (
|
|
255
|
+
f"{method} {path}: backend refused DB work ({refusal.error_code}) on "
|
|
256
|
+
f"{attempts} attempts over {waited_seconds:.1f}s; last component="
|
|
257
|
+
f"{refusal.component} work_class={refusal.work_class} "
|
|
258
|
+
f"retry_after={refusal.retry_after_seconds} status={refusal.status} "
|
|
259
|
+
f"operator_action={refusal.operator_action}"
|
|
260
|
+
)
|
|
261
|
+
super().__init__(
|
|
262
|
+
detail,
|
|
263
|
+
failure=SynthFailure(
|
|
264
|
+
code=SynthErrorCode(DB_BACKPRESSURE_RETRY_EXHAUSTED_CODE),
|
|
265
|
+
category=SynthErrorCategory.TRANSIENT_SERVICE,
|
|
266
|
+
operation=operation_id,
|
|
267
|
+
request_id=None,
|
|
268
|
+
correlation_id=None,
|
|
269
|
+
retry=RetryDirective(
|
|
270
|
+
retryable=False,
|
|
271
|
+
retry_after_seconds=refusal.retry_after_seconds,
|
|
272
|
+
),
|
|
273
|
+
status=refusal.status,
|
|
274
|
+
detail=detail,
|
|
275
|
+
reason=refusal.component,
|
|
276
|
+
),
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
@property
|
|
280
|
+
def component(self) -> str | None:
|
|
281
|
+
return self.refusal.component
|
|
282
|
+
|
|
283
|
+
@property
|
|
284
|
+
def work_class(self) -> str | None:
|
|
285
|
+
return self.refusal.work_class
|
|
286
|
+
|
|
287
|
+
@property
|
|
288
|
+
def retry_after_seconds(self) -> float | None:
|
|
289
|
+
return self.refusal.retry_after_seconds
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
__all__ = [
|
|
293
|
+
"DB_BACKPRESSURE_ERROR_CODE",
|
|
294
|
+
"DbBackpressureRefusal",
|
|
295
|
+
"DbBackpressureRetryExhaustedError",
|
|
296
|
+
"DbBackpressureRetryPolicy",
|
|
297
|
+
"request_permits_replay",
|
|
298
|
+
"RetryPolicy",
|
|
299
|
+
"idempotency_key_from_request",
|
|
300
|
+
"retry_after_from_error",
|
|
301
|
+
"should_retry_failure",
|
|
302
|
+
]
|
|
@@ -7,6 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
9
|
import math
|
|
10
|
+
import random
|
|
10
11
|
import time
|
|
11
12
|
from collections.abc import Callable, Iterator, Mapping
|
|
12
13
|
from dataclasses import dataclass, field
|
|
@@ -37,7 +38,12 @@ from synth_ai.core.errors import (
|
|
|
37
38
|
)
|
|
38
39
|
from synth_ai.core.http.request import HttpRequest
|
|
39
40
|
from synth_ai.core.http.retry import (
|
|
41
|
+
DB_BACKPRESSURE_ERROR_CODE,
|
|
42
|
+
DbBackpressureRefusal,
|
|
43
|
+
DbBackpressureRetryExhaustedError,
|
|
44
|
+
DbBackpressureRetryPolicy,
|
|
40
45
|
RetryPolicy,
|
|
46
|
+
request_permits_replay,
|
|
41
47
|
retry_after_from_error,
|
|
42
48
|
should_retry_failure,
|
|
43
49
|
)
|
|
@@ -118,7 +124,7 @@ def _declares_runtime_unavailable(decoded: JsonValue | None) -> bool:
|
|
|
118
124
|
return False
|
|
119
125
|
nested = decoded.get("detail")
|
|
120
126
|
return any(
|
|
121
|
-
source.get(key) in RUNTIME_UNAVAILABLE_CODES
|
|
127
|
+
isinstance(source.get(key), str) and source.get(key) in RUNTIME_UNAVAILABLE_CODES
|
|
122
128
|
for source in (nested, decoded)
|
|
123
129
|
if isinstance(source, dict)
|
|
124
130
|
for key in ("error_code", "code", "error")
|
|
@@ -206,6 +212,37 @@ SEARCH_ID_HEADER = "x-synth-search-id"
|
|
|
206
212
|
SEARCH_RESOURCE_KIND = "index_search"
|
|
207
213
|
|
|
208
214
|
|
|
215
|
+
def db_backpressure_refusal(response: httpx.Response) -> DbBackpressureRefusal | None:
|
|
216
|
+
"""Decode the backend's typed DB backpressure refusal, or None for any other error."""
|
|
217
|
+
if response.status_code not in {429, 503}:
|
|
218
|
+
return None
|
|
219
|
+
try:
|
|
220
|
+
decoded = response.json()
|
|
221
|
+
except (json.JSONDecodeError, ValueError):
|
|
222
|
+
return None
|
|
223
|
+
if not isinstance(decoded, dict):
|
|
224
|
+
return None
|
|
225
|
+
detail = decoded.get("detail")
|
|
226
|
+
body = detail if isinstance(detail, dict) else decoded
|
|
227
|
+
if DB_BACKPRESSURE_ERROR_CODE not in (body.get("error_code"), body.get("failure_class")):
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
def text(key: str) -> str | None:
|
|
231
|
+
value = body.get(key)
|
|
232
|
+
return value if isinstance(value, str) and value.strip() else None
|
|
233
|
+
|
|
234
|
+
retry_after = _retry_after_seconds(response, sources=(cast(JsonObject, body),))
|
|
235
|
+
return DbBackpressureRefusal(
|
|
236
|
+
status=response.status_code,
|
|
237
|
+
error_code=DB_BACKPRESSURE_ERROR_CODE,
|
|
238
|
+
component=text("component"),
|
|
239
|
+
work_class=text("work_class"),
|
|
240
|
+
retry_after_seconds=retry_after,
|
|
241
|
+
operator_action=text("operator_action"),
|
|
242
|
+
message=text("message") or "database work rejected before starting",
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
209
246
|
def _created_search(
|
|
210
247
|
response: httpx.Response, sources: tuple[JsonObject, ...]
|
|
211
248
|
) -> ResourceRef | None:
|
|
@@ -388,12 +425,19 @@ class HttpTransport:
|
|
|
388
425
|
"""One strict sync transport for JSON, bytes, and SSE operations."""
|
|
389
426
|
|
|
390
427
|
base_url: str
|
|
391
|
-
headers: Mapping[str, str]
|
|
428
|
+
headers: Mapping[str, str] = field(repr=False)
|
|
392
429
|
timeout_seconds: float = 30.0
|
|
393
430
|
retry_policy: RetryPolicy = field(default_factory=RetryPolicy)
|
|
394
431
|
error_handler: ErrorHandler = raise_http_error
|
|
395
432
|
exception_handler: ExceptionHandler = raise_transport_exception
|
|
396
433
|
decode_error_handler: DecodeErrorHandler = raise_json_decode_error
|
|
434
|
+
follow_redirects: bool = True
|
|
435
|
+
db_backpressure_policy: DbBackpressureRetryPolicy = field(
|
|
436
|
+
default_factory=DbBackpressureRetryPolicy
|
|
437
|
+
)
|
|
438
|
+
sleep: Callable[[float], None] = time.sleep
|
|
439
|
+
monotonic: Callable[[], float] = time.monotonic
|
|
440
|
+
rng: random.Random = field(default_factory=random.Random, repr=False)
|
|
397
441
|
client: httpx.Client = field(init=False, repr=False)
|
|
398
442
|
|
|
399
443
|
def __post_init__(self) -> None:
|
|
@@ -402,7 +446,7 @@ class HttpTransport:
|
|
|
402
446
|
headers=dict(self.headers),
|
|
403
447
|
timeout=self.timeout_seconds,
|
|
404
448
|
limits=httpx.Limits(max_keepalive_connections=0),
|
|
405
|
-
follow_redirects=
|
|
449
|
+
follow_redirects=self.follow_redirects,
|
|
406
450
|
)
|
|
407
451
|
|
|
408
452
|
def close(self) -> None:
|
|
@@ -420,19 +464,44 @@ class HttpTransport:
|
|
|
420
464
|
timeout_seconds: float | None = None,
|
|
421
465
|
operation_id: str | None = None,
|
|
422
466
|
) -> JsonValue:
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
467
|
+
replay_safe = request_permits_replay(method, {**self.headers, **(headers or {})})
|
|
468
|
+
attempts = 0
|
|
469
|
+
waited_seconds = 0.0
|
|
470
|
+
while True:
|
|
471
|
+
try:
|
|
472
|
+
response = self.client.request(
|
|
473
|
+
method,
|
|
474
|
+
path,
|
|
475
|
+
params=cast(Any, params),
|
|
476
|
+
json=json_body,
|
|
477
|
+
headers=headers,
|
|
478
|
+
timeout=self.timeout_seconds if timeout_seconds is None else timeout_seconds,
|
|
479
|
+
)
|
|
480
|
+
except httpx.TimeoutException as exc:
|
|
481
|
+
self.exception_handler(method, path, exc, operation_id)
|
|
482
|
+
except httpx.TransportError as exc:
|
|
483
|
+
self.exception_handler(method, path, exc, operation_id)
|
|
484
|
+
attempts += 1
|
|
485
|
+
refusal = db_backpressure_refusal(response) if replay_safe else None
|
|
486
|
+
if refusal is None:
|
|
487
|
+
break
|
|
488
|
+
delay = self.db_backpressure_policy.next_delay_seconds(
|
|
489
|
+
attempts_made=attempts,
|
|
490
|
+
waited_seconds=waited_seconds,
|
|
491
|
+
refusal=refusal,
|
|
492
|
+
rng=self.rng,
|
|
431
493
|
)
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
494
|
+
if delay is None:
|
|
495
|
+
raise DbBackpressureRetryExhaustedError(
|
|
496
|
+
method=method,
|
|
497
|
+
path=path,
|
|
498
|
+
operation_id=operation_id,
|
|
499
|
+
refusal=refusal,
|
|
500
|
+
attempts=attempts,
|
|
501
|
+
waited_seconds=waited_seconds,
|
|
502
|
+
)
|
|
503
|
+
self.sleep(delay)
|
|
504
|
+
waited_seconds += delay
|
|
436
505
|
if allow_not_found and response.status_code == 404:
|
|
437
506
|
return None
|
|
438
507
|
if response.is_error:
|
|
@@ -598,6 +667,7 @@ class HttpTransport:
|
|
|
598
667
|
|
|
599
668
|
|
|
600
669
|
__all__ = [
|
|
670
|
+
"db_backpressure_refusal",
|
|
601
671
|
"ErrorHandler",
|
|
602
672
|
"ExceptionHandler",
|
|
603
673
|
"DecodeErrorHandler",
|
|
@@ -7,6 +7,7 @@ from synth_ai.mcp.research.tools.factories import build_factory_tools
|
|
|
7
7
|
from synth_ai.mcp.research.tools.files import build_file_tools
|
|
8
8
|
from synth_ai.mcp.research.tools.image_releases import build_image_release_tools
|
|
9
9
|
from synth_ai.mcp.research.tools.intern_program import build_intern_program_tools
|
|
10
|
+
from synth_ai.mcp.research.tools.local_files import SelectedFileReader
|
|
10
11
|
from synth_ai.mcp.research.tools.models import build_model_tools
|
|
11
12
|
from synth_ai.mcp.research.tools.outputs import build_output_tools
|
|
12
13
|
from synth_ai.mcp.research.tools.progress import build_progress_tools
|
|
@@ -21,6 +22,7 @@ from synth_ai.mcp.research.tools.visuals import build_visual_tools
|
|
|
21
22
|
from synth_ai.mcp.research.tools.workspace_inputs import build_workspace_input_tools
|
|
22
23
|
|
|
23
24
|
__all__ = [
|
|
25
|
+
"SelectedFileReader",
|
|
24
26
|
"build_dataset_tools",
|
|
25
27
|
"build_environment_tools",
|
|
26
28
|
"build_export_tools",
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Dependency-clean implementation of the public Synth Research SDK."""
|
|
2
|
+
|
|
3
|
+
from synth_ai.sdk.research.client import AsyncClient, Client
|
|
4
|
+
from synth_ai.sdk.research.contracts.resource_reads import (
|
|
5
|
+
DataPoolReadReference,
|
|
6
|
+
DatasetRevisionReadReference,
|
|
7
|
+
ProjectDataPoolDescriptor,
|
|
8
|
+
ProjectDataPoolInventory,
|
|
9
|
+
)
|
|
10
|
+
from synth_ai.sdk.research.facade import ResearchClient
|
|
11
|
+
from synth_ai.sdk.research.hierarchy import AsyncHierarchyClient, HierarchyClient
|
|
12
|
+
from synth_ai.sdk.research.hierarchy_models import (
|
|
13
|
+
EntityKey,
|
|
14
|
+
HierarchyCommand,
|
|
15
|
+
HierarchyOriginal,
|
|
16
|
+
HierarchyRead,
|
|
17
|
+
HierarchyScope,
|
|
18
|
+
)
|
|
19
|
+
from synth_ai.sdk.research.operations import RESEARCH_OPERATIONS, research_operation
|
|
20
|
+
from synth_ai.sdk.research.owner_reads import (
|
|
21
|
+
AsyncOwnerReadClient,
|
|
22
|
+
OwnerReadAccess,
|
|
23
|
+
OwnerReadAccessExpired,
|
|
24
|
+
OwnerReadAccessExpiredError,
|
|
25
|
+
OwnerReadClient,
|
|
26
|
+
OwnerReadScope,
|
|
27
|
+
)
|
|
28
|
+
from synth_ai.sdk.research.planning_reads import (
|
|
29
|
+
AsyncPlanningReads,
|
|
30
|
+
PlanningGraphRead,
|
|
31
|
+
PlanningReadPosition,
|
|
32
|
+
PlanningReads,
|
|
33
|
+
PlanningTaskPage,
|
|
34
|
+
PlanningTaskRead,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
AsyncResearchClient = AsyncClient
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"AsyncHierarchyClient",
|
|
41
|
+
"HierarchyClient",
|
|
42
|
+
"HierarchyScope",
|
|
43
|
+
"HierarchyCommand",
|
|
44
|
+
"HierarchyRead",
|
|
45
|
+
"HierarchyOriginal",
|
|
46
|
+
"EntityKey",
|
|
47
|
+
"AsyncClient",
|
|
48
|
+
"AsyncResearchClient",
|
|
49
|
+
"AsyncOwnerReadClient",
|
|
50
|
+
"AsyncPlanningReads",
|
|
51
|
+
"Client",
|
|
52
|
+
"DataPoolReadReference",
|
|
53
|
+
"DatasetRevisionReadReference",
|
|
54
|
+
"ProjectDataPoolDescriptor",
|
|
55
|
+
"ProjectDataPoolInventory",
|
|
56
|
+
"OwnerReadAccess",
|
|
57
|
+
"OwnerReadAccessExpired",
|
|
58
|
+
"OwnerReadAccessExpiredError",
|
|
59
|
+
"OwnerReadClient",
|
|
60
|
+
"OwnerReadScope",
|
|
61
|
+
"PlanningGraphRead",
|
|
62
|
+
"PlanningReadPosition",
|
|
63
|
+
"PlanningReads",
|
|
64
|
+
"PlanningTaskPage",
|
|
65
|
+
"PlanningTaskRead",
|
|
66
|
+
"RESEARCH_OPERATIONS",
|
|
67
|
+
"ResearchClient",
|
|
68
|
+
"research_operation",
|
|
69
|
+
]
|
|
@@ -46,6 +46,16 @@ class _ResearchSession(Protocol):
|
|
|
46
46
|
|
|
47
47
|
def run(self, project_id: str, run_id: str) -> _RunHandle: ...
|
|
48
48
|
|
|
49
|
+
def get_run_results(self, project_id: str, run_id: str) -> dict[str, Any]: ...
|
|
50
|
+
|
|
51
|
+
def get_run_logs(
|
|
52
|
+
self, project_id: str, run_id: str, *, limit: int | None = None, cursor: str | None = None
|
|
53
|
+
) -> dict[str, Any]: ...
|
|
54
|
+
|
|
55
|
+
def get_run_execution(self, project_id: str, run_id: str, **kwargs: Any) -> Any: ...
|
|
56
|
+
|
|
57
|
+
def get_run_orchestrator(self, project_id: str, run_id: str) -> dict[str, Any]: ...
|
|
58
|
+
|
|
49
59
|
|
|
50
60
|
def _session_project(project: ProjectSelector | str | None) -> str | None:
|
|
51
61
|
if isinstance(project, ProjectSelector):
|
|
@@ -588,13 +598,16 @@ class ResearchRunsAPI:
|
|
|
588
598
|
from synth_ai.sdk.pagination import page_from_wire
|
|
589
599
|
|
|
590
600
|
payload = self.logs(project_id, run_id, limit=limit, cursor=cursor)
|
|
601
|
+
if isinstance(payload, dict) and "items" not in payload and "data" not in payload:
|
|
602
|
+
for field_name in ("entries", "logs", "records"):
|
|
603
|
+
if field_name in payload:
|
|
604
|
+
payload = {
|
|
605
|
+
"items": payload[field_name],
|
|
606
|
+
"next_cursor": payload.get("next_cursor"),
|
|
607
|
+
"has_more": payload.get("has_more", False),
|
|
608
|
+
}
|
|
609
|
+
break
|
|
591
610
|
raw_items, next_cursor, has_more = page_from_wire(payload)
|
|
592
|
-
if isinstance(payload, dict) and isinstance(payload.get("entries"), list):
|
|
593
|
-
raw_items = payload["entries"]
|
|
594
|
-
elif isinstance(payload, dict) and isinstance(payload.get("logs"), list):
|
|
595
|
-
raw_items = payload["logs"]
|
|
596
|
-
elif isinstance(payload, dict) and isinstance(payload.get("records"), list):
|
|
597
|
-
raw_items = payload["records"]
|
|
598
611
|
normalized = [cast(dict[str, Any], item) for item in raw_items if isinstance(item, dict)]
|
|
599
612
|
return SyncPage(items=normalized, next_cursor=next_cursor, has_more=has_more)
|
|
600
613
|
|