synth-ai 0.22.2.dev687__tar.gz → 0.22.2.dev689__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.dev687/synth_ai.egg-info → synth_ai-0.22.2.dev689}/PKG-INFO +1 -1
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/pyproject.toml +1 -1
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/index.py +1 -1
- synth_ai-0.22.2.dev689/synth_ai/core/http/retry.py +302 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/http/transport.py +81 -12
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/registry.py +1 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/server.py +9 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/index.py +2 -22
- synth_ai-0.22.2.dev689/synth_ai/mcp/research/tools/local_files.py +5 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/runs.py +13 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/scientific_records.py +12 -1
- synth_ai-0.22.2.dev689/synth_ai/sdk/index/local_files.py +32 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/upload_session.py +1 -1
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/__init__.py +8 -0
- synth_ai-0.22.2.dev689/synth_ai/sdk/research/contracts/forge_citations.py +29 -0
- synth_ai-0.22.2.dev689/synth_ai/sdk/research/contracts/forge_uploads.py +84 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/runtime_intent.py +40 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/status.py +81 -9
- synth_ai-0.22.2.dev689/synth_ai/sdk/research/contracts/swarm_history.py +167 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/operations.py +6 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/scientific_records.py +137 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/_client_helpers.py +24 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/client.py +54 -38
- synth_ai-0.22.2.dev689/synth_ai/sdk/research/session/directory_inputs.py +243 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/swarms.py +39 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689/synth_ai.egg-info}/PKG-INFO +1 -1
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai.egg-info/SOURCES.txt +6 -0
- synth_ai-0.22.2.dev687/synth_ai/core/http/retry.py +0 -135
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/LICENSE +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/MANIFEST.in +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/openapi/index-v1.json +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/openapi/messaging-v1.json +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/openapi/research-v1.json +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/setup.cfg +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/setup.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/__main__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/AGENTS.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/__main__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/main.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/research.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/research_environments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/research_image_releases.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/research_projects.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/utils/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/cli/utils/research_launch.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/client.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/auth/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/auth/credentials.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/contracts/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/contracts/json_value.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/contracts/pagination.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/errors.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/http/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/http/async_transport.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/http/request.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/http/streaming.py +0 -0
- {synth_ai-0.22.2.dev687/synth_ai/mcp/research/tools → synth_ai-0.22.2.dev689/synth_ai/core}/local_files.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/research/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/utils/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/utils/env.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/utils/log_filter.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/utils/paths.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/core/utils/urls.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/__main__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/objective_tools.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/request_models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/approvals.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/artifacts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/datasets.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/environments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/exports.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/factories.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/factory_results.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/files.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/image_releases.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/index_qa.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/integrations.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/intern_program.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/launch_schemas.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/logs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/outputs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/policy_schemas.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/progress.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/project_data.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/projects.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/prs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/readiness.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/repos.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/research_intern.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/resource_reads.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/resources.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/trained_models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/usage.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/visuals.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/workspace_inputs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/pools.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/py.typed +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/AGENT_SETUP_PROMPT.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/agent_policy.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/artifacts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/catalog.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/catalogue.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/classification.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/client.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/contracts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/contributions.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/errors.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/forge_notices.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/intake.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/lifecycle.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/manifest.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/oauth.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/package.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/public.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/public_corpus.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/public_search.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/qa.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/qa_checks.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/qa_preflight.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/qa_reviews.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/research/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/research/build.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/research/capture.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/research/contracts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/research/files.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/research/release.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/research_intake.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/retry.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/rights.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/scientific_provenance.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/scope_errors.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/scopes.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/search.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/submission.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/timeouts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/transfer.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/usage_accounting.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/value.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/index/wallet_search.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/messaging/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/messaging/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/messaging/client.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/messaging/contracts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/optimizers/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/optimizers/client.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/optimizers/contracts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/pagination.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/_internal/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/_internal/crypto.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/_internal/env.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/_internal/urls.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/account.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/advanced.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/advanced_factories.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/advanced_swarms.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/artifacts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/auth.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/client.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/container_pools/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/container_pools/api.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/container_pools/contracts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/container_pools/operations.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/container_pools/packaging.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/_activity_wire.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/_environment_wire.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/_transcript_wire.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/_wire.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/activity.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/activity_items.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/actor_images.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/billing.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/canonical_usage.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/checkpoints.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/cloud_deployment_claims.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/cloud_deployments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/common.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/dataset_revisions.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/deliveries.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/dev_environment_evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/economics.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/environment_manifest.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/environments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/experiment_evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/factories.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/factory_evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/factory_lenses.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/factory_operations.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/factory_role_receipts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/failure.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/contracts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/evaluation.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/exports.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/operations.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/records.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/resources.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/forge/schema.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/image_releases.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/intern_authority.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/intern_blockers.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/intern_grants.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/intern_program.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/intern_resources.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/intern_usage.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/limit_evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/local_execution_profile.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/native_attachment.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/native_result_outcome.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/operator_evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/project.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/project_data.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/project_runtime.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/project_workspace.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/project_workspace_evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/projects.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/promotions.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/research_intern.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/resource_reads.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/resource_settlement.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_authority.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_control.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_diagnostics.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_events.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_execution.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_launch.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_observability.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_state.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/run_timeline.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/runtime_image.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/runtime_stream.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/runtime_stream_snapshot.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/scientific_citations.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/scientific_integrity.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_actor_models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_actor_policy_data.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_agent_harnesses.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_agent_kinds.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_agent_models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_branching.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_credential_providers.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_environment_kinds.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_evidence_obligations.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_funding_sources.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_horizons.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_host_kinds.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_inference_providers.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_network_topology.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_providers.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_resource_kinds.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_roles.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_run_policy.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_runbooks.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_runnable_project.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_runtime_kinds.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_tool_providers.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/smr_work_modes.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/swarm_controls.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/swarm_rollouts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/swarm_tasks.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/swarms.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/tag.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/traces.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/transcript.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/types.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/usage.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/visuals.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/wire_models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/wire_models_README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/work_products.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/contracts/workspaces.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/economics.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/efforts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/environments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/errors.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/events.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/experiments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/facade.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/factories.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/factory_storage.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/image_releases.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/intern_authority.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/intern_blockers.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/intern_program.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/knowledge.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/project_data.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/project_deliveries.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/project_workspaces.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/projects.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/public.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/readouts.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/research_intern.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/resource_reads.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/secrets.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/README.md +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/_base.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/_run_authority_mixin.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/approvals.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/billing.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/cloud_deployments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/config.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/cost.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/datasets.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/dev_environments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/environments.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/exports.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/factories.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/factory_evidence.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/files.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/github.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/image_releases.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/images.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/logs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/outputs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/progress.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/project.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/projects.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/prs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/readiness.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/repositories.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/runs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/secrets.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/setup.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/tag.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/trained_models.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/transport.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/usage.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/work_products.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/session/workspace_inputs.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/surface_parity.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/traces.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/transport/__init__.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/transport/http.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/transport/pagination.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/version.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/visuals.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/sdk/research/wiki.py +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai.egg-info/dependency_links.txt +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai.egg-info/entry_points.txt +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai.egg-info/requires.txt +0 -0
- {synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/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.dev689"
|
|
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"}]
|
|
@@ -633,8 +633,8 @@ def contribution_status(contribution_id, revision_id, search_id, api_key, backen
|
|
|
633
633
|
@_lifecycle_target_options
|
|
634
634
|
def contribution_upload(draft_file, upload_spec_file, root, files, api_key, backend_url):
|
|
635
635
|
"""Prepare, transfer exactly the selected files, then finalize. Does not submit."""
|
|
636
|
-
from synth_ai.mcp.research.tools.index import read_selected_files
|
|
637
636
|
from synth_ai.sdk.index.contributions import ContributionDraft, ContributionUploadSpec
|
|
637
|
+
from synth_ai.sdk.index.local_files import read_selected_files
|
|
638
638
|
|
|
639
639
|
selected: dict[str, str] = {}
|
|
640
640
|
for item in files:
|
|
@@ -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
|
)
|
|
@@ -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:
|
|
@@ -394,6 +431,12 @@ class HttpTransport:
|
|
|
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
|
+
db_backpressure_policy: DbBackpressureRetryPolicy = field(
|
|
435
|
+
default_factory=DbBackpressureRetryPolicy
|
|
436
|
+
)
|
|
437
|
+
sleep: Callable[[float], None] = time.sleep
|
|
438
|
+
monotonic: Callable[[], float] = time.monotonic
|
|
439
|
+
rng: random.Random = field(default_factory=random.Random, repr=False)
|
|
397
440
|
client: httpx.Client = field(init=False, repr=False)
|
|
398
441
|
|
|
399
442
|
def __post_init__(self) -> None:
|
|
@@ -420,19 +463,44 @@ class HttpTransport:
|
|
|
420
463
|
timeout_seconds: float | None = None,
|
|
421
464
|
operation_id: str | None = None,
|
|
422
465
|
) -> JsonValue:
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
466
|
+
replay_safe = request_permits_replay(method, {**self.headers, **(headers or {})})
|
|
467
|
+
attempts = 0
|
|
468
|
+
waited_seconds = 0.0
|
|
469
|
+
while True:
|
|
470
|
+
try:
|
|
471
|
+
response = self.client.request(
|
|
472
|
+
method,
|
|
473
|
+
path,
|
|
474
|
+
params=cast(Any, params),
|
|
475
|
+
json=json_body,
|
|
476
|
+
headers=headers,
|
|
477
|
+
timeout=self.timeout_seconds if timeout_seconds is None else timeout_seconds,
|
|
478
|
+
)
|
|
479
|
+
except httpx.TimeoutException as exc:
|
|
480
|
+
self.exception_handler(method, path, exc, operation_id)
|
|
481
|
+
except httpx.TransportError as exc:
|
|
482
|
+
self.exception_handler(method, path, exc, operation_id)
|
|
483
|
+
attempts += 1
|
|
484
|
+
refusal = db_backpressure_refusal(response) if replay_safe else None
|
|
485
|
+
if refusal is None:
|
|
486
|
+
break
|
|
487
|
+
delay = self.db_backpressure_policy.next_delay_seconds(
|
|
488
|
+
attempts_made=attempts,
|
|
489
|
+
waited_seconds=waited_seconds,
|
|
490
|
+
refusal=refusal,
|
|
491
|
+
rng=self.rng,
|
|
431
492
|
)
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
493
|
+
if delay is None:
|
|
494
|
+
raise DbBackpressureRetryExhaustedError(
|
|
495
|
+
method=method,
|
|
496
|
+
path=path,
|
|
497
|
+
operation_id=operation_id,
|
|
498
|
+
refusal=refusal,
|
|
499
|
+
attempts=attempts,
|
|
500
|
+
waited_seconds=waited_seconds,
|
|
501
|
+
)
|
|
502
|
+
self.sleep(delay)
|
|
503
|
+
waited_seconds += delay
|
|
436
504
|
if allow_not_found and response.status_code == 404:
|
|
437
505
|
return None
|
|
438
506
|
if response.is_error:
|
|
@@ -598,6 +666,7 @@ class HttpTransport:
|
|
|
598
666
|
|
|
599
667
|
|
|
600
668
|
__all__ = [
|
|
669
|
+
"db_backpressure_refusal",
|
|
601
670
|
"ErrorHandler",
|
|
602
671
|
"ExceptionHandler",
|
|
603
672
|
"DecodeErrorHandler",
|
|
@@ -109,6 +109,7 @@ _DEFAULT_REQUIRED_SCOPES_BY_TOOL_NAME: dict[str, tuple[str, ...]] = {
|
|
|
109
109
|
"research_get_run": READ_SCOPES,
|
|
110
110
|
"research_get_swarm_activity": READ_SCOPES,
|
|
111
111
|
"research_get_swarm_configuration": READ_SCOPES,
|
|
112
|
+
"research_get_run_history": READ_SCOPES,
|
|
112
113
|
"research_get_swarm_evidence": READ_SCOPES,
|
|
113
114
|
"research_get_swarm_usage": READ_SCOPES,
|
|
114
115
|
"research_get_run_execution": READ_SCOPES,
|
|
@@ -173,6 +173,7 @@ _STABLE_TOOL_NAMES = RESOURCE_READ_TOOL_NAMES | frozenset(
|
|
|
173
173
|
"research_get_record",
|
|
174
174
|
"research_get_record_citations",
|
|
175
175
|
"research_get_native_attachments",
|
|
176
|
+
"research_verify_citations",
|
|
176
177
|
"research_list_records",
|
|
177
178
|
"research_get_operation_receipt",
|
|
178
179
|
"research_record_events",
|
|
@@ -192,6 +193,7 @@ _STABLE_TOOL_NAMES = RESOURCE_READ_TOOL_NAMES | frozenset(
|
|
|
192
193
|
"research_get_run_transcript",
|
|
193
194
|
"research_get_swarm_activity",
|
|
194
195
|
"research_get_swarm_configuration",
|
|
196
|
+
"research_get_run_history",
|
|
195
197
|
"research_get_swarm_evidence",
|
|
196
198
|
"research_get_swarm_status",
|
|
197
199
|
"research_get_swarm_usage",
|
|
@@ -2015,6 +2017,13 @@ class ResearchMcpServer:
|
|
|
2015
2017
|
result = client.runs.get(run_id, project_id=project_id)
|
|
2016
2018
|
return asdict(result) if is_dataclass(result) else result
|
|
2017
2019
|
|
|
2020
|
+
def _tool_get_run_history(self, args: JSONDict) -> JSONDict:
|
|
2021
|
+
run_id = SwarmId(require_string(args, "run_id"))
|
|
2022
|
+
after = _optional_int_default(args, "after", 0)
|
|
2023
|
+
limit = _optional_int_default(args, "limit", 100)
|
|
2024
|
+
with self._core_client_from_args(args) as client:
|
|
2025
|
+
return client.swarms.history(run_id, after=after, limit=limit).to_wire()
|
|
2026
|
+
|
|
2018
2027
|
def _tool_get_swarm_configuration(self, args: JSONDict) -> JSONDict:
|
|
2019
2028
|
swarm_id = SwarmId(require_string(args, "run_id"))
|
|
2020
2029
|
with self._core_client_from_args(args) as client:
|
|
@@ -7,8 +7,7 @@ Upload reads only explicitly listed files under an explicit root: this stdio ser
|
|
|
7
7
|
runs on the caller's machine; the hosted server cannot read a client's disk.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
import
|
|
11
|
-
from collections.abc import Callable, Mapping
|
|
10
|
+
from collections.abc import Callable
|
|
12
11
|
from contextlib import AbstractContextManager
|
|
13
12
|
from typing import Annotated
|
|
14
13
|
|
|
@@ -24,11 +23,11 @@ from synth_ai.mcp.research.tools.index_qa import (
|
|
|
24
23
|
QA_READ_TOOL_NAMES,
|
|
25
24
|
build_qa_tools,
|
|
26
25
|
)
|
|
27
|
-
from synth_ai.mcp.research.tools.local_files import SelectedFileReader
|
|
28
26
|
from synth_ai.sdk.index.catalog import PublicSearchCapability
|
|
29
27
|
from synth_ai.sdk.index.client import STATUS_POLL_TIMEOUT_SECONDS, IndexAPI, PublicIndexAPI
|
|
30
28
|
from synth_ai.sdk.index.contracts import ContributionReference, Identifier, IndexContract
|
|
31
29
|
from synth_ai.sdk.index.contributions import ContributionDraft, ContributionUploadSpec
|
|
30
|
+
from synth_ai.sdk.index.local_files import read_selected_files
|
|
32
31
|
from synth_ai.sdk.index.public_search import (
|
|
33
32
|
DEFAULT_PUBLIC_SEARCH_WAIT_SECONDS,
|
|
34
33
|
PublicSearchDisabledError,
|
|
@@ -75,11 +74,6 @@ INDEX_WRITE_TOOL_NAMES: tuple[str, ...] = (
|
|
|
75
74
|
)
|
|
76
75
|
INDEX_TOOL_NAMES = frozenset(INDEX_READ_TOOL_NAMES + INDEX_WRITE_TOOL_NAMES)
|
|
77
76
|
|
|
78
|
-
_UPLOAD_MAX_BYTES = 64 * 1024 * 1024
|
|
79
|
-
_CREDENTIAL = re.compile(
|
|
80
|
-
rb"(sk-[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16}|-----BEGIN [A-Z ]*PRIVATE KEY"
|
|
81
|
-
rb"|ghp_[A-Za-z0-9]{30,}|xox[bpa]-[A-Za-z0-9-]{10,})"
|
|
82
|
-
)
|
|
83
77
|
_KEY = Field(min_length=1, max_length=128, pattern=r"^[a-zA-Z0-9_.-]+$")
|
|
84
78
|
|
|
85
79
|
|
|
@@ -158,20 +152,6 @@ class SubmitRequest(IndexContract):
|
|
|
158
152
|
spec: ContributionSubmitSpec
|
|
159
153
|
|
|
160
154
|
|
|
161
|
-
def read_selected_files(root: str, files: Mapping[str, str]) -> dict[str, bytes]:
|
|
162
|
-
"""Read exactly the listed regular files; reject escapes, symlinks and secrets."""
|
|
163
|
-
content: dict[str, bytes] = {}
|
|
164
|
-
total = 0
|
|
165
|
-
with SelectedFileReader(root) as reader:
|
|
166
|
-
for logical_path, relative in files.items():
|
|
167
|
-
data = reader.read(relative, _UPLOAD_MAX_BYTES - total)
|
|
168
|
-
total += len(data)
|
|
169
|
-
if _CREDENTIAL.search(data):
|
|
170
|
-
raise ValueError(f"{logical_path}: possible credential; remove it before upload")
|
|
171
|
-
content[logical_path] = data
|
|
172
|
-
return content
|
|
173
|
-
|
|
174
|
-
|
|
175
155
|
_PUBLIC_SEARCH_DESCRIPTION = (
|
|
176
156
|
"Search reviewed Synth Index Contributions (Index Search v0.2). Without an API key "
|
|
177
157
|
"this is the free public search; mode is fast (synchronous) or deep (admitted, then "
|
|
@@ -821,6 +821,19 @@ def build_run_tools(server: Any) -> list[ToolDefinition]:
|
|
|
821
821
|
),
|
|
822
822
|
handler=server._tool_get_run,
|
|
823
823
|
),
|
|
824
|
+
ToolDefinition(
|
|
825
|
+
name="research_get_run_history",
|
|
826
|
+
description="Read a bounded backend-authorized journal page with decision reasons and redacted inputs.",
|
|
827
|
+
input_schema=tool_schema(
|
|
828
|
+
{
|
|
829
|
+
"run_id": {"type": "string", "description": "Research run id."},
|
|
830
|
+
"after": {"type": "integer", "minimum": 0, "maximum": 2**64 - 1},
|
|
831
|
+
"limit": {"type": "integer", "minimum": 1, "maximum": 256},
|
|
832
|
+
},
|
|
833
|
+
required=["run_id"],
|
|
834
|
+
),
|
|
835
|
+
handler=server._tool_get_run_history,
|
|
836
|
+
),
|
|
824
837
|
ToolDefinition(
|
|
825
838
|
name="research_get_swarm_configuration",
|
|
826
839
|
description=(
|
{synth_ai-0.22.2.dev687 → synth_ai-0.22.2.dev689}/synth_ai/mcp/research/tools/scientific_records.py
RENAMED
|
@@ -58,6 +58,14 @@ class EventArguments(Contract):
|
|
|
58
58
|
limit: int = Field(default=100, ge=1, le=1000)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
READ_DESCRIPTIONS = {
|
|
62
|
+
"research_verify_citations": (
|
|
63
|
+
"Check a retained record revision's external citations: retained, dangling, "
|
|
64
|
+
"denied, conflict, unavailable or refused. Read-only."
|
|
65
|
+
),
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
61
69
|
def build_scientific_record_tools(client_factory):
|
|
62
70
|
def execution_writer(arguments):
|
|
63
71
|
selected = ExecutionWriteArguments.model_validate(arguments)
|
|
@@ -159,6 +167,7 @@ def build_scientific_record_tools(client_factory):
|
|
|
159
167
|
)
|
|
160
168
|
for name, model, method in (
|
|
161
169
|
("research_get_record", ReadArguments, "get"),
|
|
170
|
+
("research_verify_citations", ReadArguments, "verify_citations"),
|
|
162
171
|
("research_list_records", ListArguments, "list"),
|
|
163
172
|
("research_get_operation_receipt", ReceiptArguments, "receipt"),
|
|
164
173
|
("research_record_events", EventArguments, "events"),
|
|
@@ -180,7 +189,9 @@ def build_scientific_record_tools(client_factory):
|
|
|
180
189
|
tools.append(
|
|
181
190
|
ToolDefinition(
|
|
182
191
|
name=name,
|
|
183
|
-
description=
|
|
192
|
+
description=READ_DESCRIPTIONS.get(
|
|
193
|
+
name, "Read scoped retained scientific evidence."
|
|
194
|
+
),
|
|
184
195
|
input_schema=model.model_json_schema(),
|
|
185
196
|
handler=reader(model, method),
|
|
186
197
|
required_scopes=READ_SCOPES,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Explicit, bounded local bytes shared by Index SDK, CLI and MCP uploads.
|
|
2
|
+
|
|
3
|
+
# See: synth_ai/core/local_files.py (descriptor confinement)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
from collections.abc import Mapping
|
|
8
|
+
|
|
9
|
+
from synth_ai.core.local_files import SelectedFileReader
|
|
10
|
+
|
|
11
|
+
_UPLOAD_MAX_BYTES = 64 * 1024 * 1024
|
|
12
|
+
_CREDENTIAL = re.compile(
|
|
13
|
+
rb"(sk-[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16}|-----BEGIN [A-Z ]*PRIVATE KEY"
|
|
14
|
+
rb"|ghp_[A-Za-z0-9]{30,}|xox[bpa]-[A-Za-z0-9-]{10,})"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def read_selected_files(root: str, files: Mapping[str, str]) -> dict[str, bytes]:
|
|
19
|
+
"""Read exactly the listed regular files; reject escapes, symlinks and secrets."""
|
|
20
|
+
content: dict[str, bytes] = {}
|
|
21
|
+
total = 0
|
|
22
|
+
with SelectedFileReader(root) as reader:
|
|
23
|
+
for logical_path, relative in files.items():
|
|
24
|
+
data = reader.read(relative, _UPLOAD_MAX_BYTES - total)
|
|
25
|
+
total += len(data)
|
|
26
|
+
if _CREDENTIAL.search(data):
|
|
27
|
+
raise ValueError(f"{logical_path}: possible credential; remove it before upload")
|
|
28
|
+
content[logical_path] = data
|
|
29
|
+
return content
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__ = ["read_selected_files"]
|
|
@@ -30,8 +30,8 @@ from urllib.parse import urlsplit
|
|
|
30
30
|
import httpx
|
|
31
31
|
from pydantic import ValidationError
|
|
32
32
|
|
|
33
|
-
from synth_ai.mcp.research.tools.index import read_selected_files
|
|
34
33
|
from synth_ai.sdk.index.contributions import ContributionUploadPrepared
|
|
34
|
+
from synth_ai.sdk.index.local_files import read_selected_files
|
|
35
35
|
from synth_ai.sdk.index.transfer import _transfer_content
|
|
36
36
|
|
|
37
37
|
_ACCEPTED = (200, 201, 204)
|