synth-ai 0.18.0.dev590__tar.gz → 0.18.1.dev595__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.18.0.dev590/synth_ai.egg-info → synth_ai-0.18.1.dev595}/PKG-INFO +2 -2
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/README.md +1 -1
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/pyproject.toml +1 -1
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/__init__.py +14 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/actor_images.py +21 -5
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/factories.py +5 -1
- synth_ai-0.18.1.dev595/synth_ai/sdk/research/contracts/failure.py +173 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/image_releases.py +38 -7
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_observability.py +9 -5
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/image_releases.py +142 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/public.py +10 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/runs.py +8 -13
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595/synth_ai.egg-info}/PKG-INFO +2 -2
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai.egg-info/SOURCES.txt +1 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/LICENSE +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/MANIFEST.in +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/setup.cfg +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/README.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/__main__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/AGENTS.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/README.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/__main__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/main.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/research.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/research_environments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/research_image_releases.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/cli/research_projects.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/client.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/README.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/auth/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/auth/credentials.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/contracts/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/contracts/json_value.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/contracts/pagination.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/errors.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/http/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/http/async_transport.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/http/request.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/http/retry.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/http/streaming.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/http/transport.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/research/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/utils/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/utils/env.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/utils/log_filter.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/utils/paths.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/core/utils/urls.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/README.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/__main__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/objective_tools.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/registry.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/request_models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/server.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/approvals.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/artifacts.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/datasets.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/environments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/exports.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/factories.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/factory_results.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/files.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/image_releases.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/integrations.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/logs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/outputs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/policy_schemas.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/progress.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/project_data.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/projects.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/prs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/readiness.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/repos.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/resources.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/runs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/trained_models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/usage.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/visuals.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/mcp/research/tools/workspace_inputs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/py.typed +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/README.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/pagination.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/_internal/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/_internal/crypto.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/_internal/env.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/_internal/urls.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/account.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/advanced.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/advanced_factories.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/advanced_swarms.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/artifacts.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/auth.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/client.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/_activity_wire.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/_environment_wire.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/_transcript_wire.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/_wire.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/activity.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/activity_items.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/billing.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/canonical_usage.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/checkpoints.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/cloud_deployment_claims.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/cloud_deployments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/common.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/dataset_revisions.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/deliveries.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/dev_environment_evidence.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/economics.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/environment_manifest.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/environments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/evidence.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/factory_evidence.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/factory_lenses.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/factory_operations.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/factory_role_receipts.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/local_execution_profile.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/operator_evidence.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/project.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/project_data.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/project_runtime.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/project_workspace.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/project_workspace_evidence.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/projects.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/promotions.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/research_intern.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_authority.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_control.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_diagnostics.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_events.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_execution.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_launch.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_state.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/run_timeline.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/runtime_image.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/runtime_intent.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/runtime_stream.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/runtime_stream_snapshot.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/scientific_integrity.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_actor_models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_actor_policy_data.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_agent_harnesses.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_agent_kinds.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_agent_models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_branching.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_credential_providers.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_environment_kinds.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_evidence_obligations.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_funding_sources.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_horizons.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_host_kinds.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_inference_providers.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_network_topology.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_providers.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_resource_kinds.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_roles.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_run_policy.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_runbooks.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_runnable_project.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_runtime_kinds.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_tool_providers.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/smr_work_modes.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/status.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/swarms.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/tag.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/traces.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/transcript.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/types.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/usage.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/visuals.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/wire_models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/wire_models_README.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/work_products.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/workspaces.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/economics.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/efforts.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/environments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/errors.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/events.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/experiments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/facade.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/factories.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/factory_storage.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/knowledge.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/operations.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/project_data.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/project_deliveries.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/project_workspaces.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/projects.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/readouts.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/research_intern.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/secrets.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/README.md +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/_base.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/_client_helpers.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/_run_authority_mixin.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/approvals.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/billing.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/client.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/cloud_deployments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/config.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/cost.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/datasets.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/dev_environments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/environments.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/exports.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/factories.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/factory_evidence.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/files.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/github.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/image_releases.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/images.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/logs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/outputs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/progress.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/project.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/projects.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/prs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/readiness.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/repositories.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/secrets.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/setup.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/tag.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/trained_models.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/transport.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/usage.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/work_products.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/session/workspace_inputs.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/swarms.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/traces.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/transport/__init__.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/transport/http.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/transport/pagination.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/version.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/visuals.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/wiki.py +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai.egg-info/dependency_links.txt +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai.egg-info/entry_points.txt +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai.egg-info/requires.txt +0 -0
- {synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: synth-ai
|
|
3
|
-
Version: 0.18.
|
|
3
|
+
Version: 0.18.1.dev595
|
|
4
4
|
Summary: Python SDK and CLI for Synth Managed Research and Research Factory
|
|
5
5
|
Author-email: Synth AI <josh@usesynth.ai>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -27,7 +27,7 @@ Dynamic: license-file
|
|
|
27
27
|
|
|
28
28
|
# Synth AI SDK
|
|
29
29
|
|
|
30
|
-
<!-- CI release pins: PyPI-0.18.
|
|
30
|
+
<!-- CI release pins: PyPI-0.18.1-orange synth-ai==0.18.1 -->
|
|
31
31
|
|
|
32
32
|
[](https://pypi.org/project/synth-ai/)
|
|
33
33
|
[](https://pypi.org/project/synth-ai/)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Synth AI SDK
|
|
2
2
|
|
|
3
|
-
<!-- CI release pins: PyPI-0.18.
|
|
3
|
+
<!-- CI release pins: PyPI-0.18.1-orange synth-ai==0.18.1 -->
|
|
4
4
|
|
|
5
5
|
[](https://pypi.org/project/synth-ai/)
|
|
6
6
|
[](https://pypi.org/project/synth-ai/)
|
{synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/__init__.py
RENAMED
|
@@ -177,7 +177,15 @@ from synth_ai.sdk.research.contracts.factory_role_receipts import (
|
|
|
177
177
|
FactoryRoleReceiptResponse,
|
|
178
178
|
FactoryRoleReceiptRuntimeEvidence,
|
|
179
179
|
)
|
|
180
|
+
from synth_ai.sdk.research.contracts.failure import (
|
|
181
|
+
ActorFailureReason,
|
|
182
|
+
ManagedResearchFailureClassification,
|
|
183
|
+
ManagedResearchFailureFamily,
|
|
184
|
+
ManagedResearchFailureScope,
|
|
185
|
+
ManagedResearchFailureSeverity,
|
|
186
|
+
)
|
|
180
187
|
from synth_ai.sdk.research.contracts.image_releases import (
|
|
188
|
+
ActorImageCapability,
|
|
181
189
|
ActorRuntimeImageMaterialization,
|
|
182
190
|
ActorRuntimeImageRelease,
|
|
183
191
|
ActorRuntimeImageReleaseArchive,
|
|
@@ -475,6 +483,7 @@ def __getattr__(name: str) -> object:
|
|
|
475
483
|
|
|
476
484
|
|
|
477
485
|
__all__ = [
|
|
486
|
+
"ActorFailureReason",
|
|
478
487
|
"DataBindingCreateRequest",
|
|
479
488
|
"DataBindingResponse",
|
|
480
489
|
"DatasetRevisionContent",
|
|
@@ -512,6 +521,10 @@ __all__ = [
|
|
|
512
521
|
"MagiDecisionReceiptResponse",
|
|
513
522
|
"MagiDecisionRequest",
|
|
514
523
|
"MagiMode",
|
|
524
|
+
"ManagedResearchFailureClassification",
|
|
525
|
+
"ManagedResearchFailureFamily",
|
|
526
|
+
"ManagedResearchFailureScope",
|
|
527
|
+
"ManagedResearchFailureSeverity",
|
|
515
528
|
"ActivityActor",
|
|
516
529
|
"ActivityActorState",
|
|
517
530
|
"ActivityCursor",
|
|
@@ -530,6 +543,7 @@ __all__ = [
|
|
|
530
543
|
"ActiveActorModel",
|
|
531
544
|
"ActorHarness",
|
|
532
545
|
"ActorImageBinding",
|
|
546
|
+
"ActorImageCapability",
|
|
533
547
|
"ActorModel",
|
|
534
548
|
"ActorModelAssignment",
|
|
535
549
|
"ActorSubtype",
|
{synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/actor_images.py
RENAMED
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
from collections.abc import Mapping
|
|
12
12
|
from dataclasses import dataclass
|
|
13
13
|
from typing import TypeAlias
|
|
14
|
+
from uuid import UUID
|
|
14
15
|
|
|
15
16
|
ACTOR_IMAGE_ROLES: tuple[str, ...] = (
|
|
16
17
|
"orchestrator",
|
|
@@ -28,14 +29,21 @@ class ActorImageBinding:
|
|
|
28
29
|
notes: str | None = None
|
|
29
30
|
|
|
30
31
|
def __post_init__(self) -> None:
|
|
31
|
-
if not isinstance(self.release_id, str)
|
|
32
|
-
raise ValueError("ActorImageBinding.release_id must be a
|
|
32
|
+
if not isinstance(self.release_id, str):
|
|
33
|
+
raise ValueError("ActorImageBinding.release_id must be a UUID string")
|
|
34
|
+
try:
|
|
35
|
+
release_id = str(UUID(self.release_id.strip()))
|
|
36
|
+
except (AttributeError, ValueError) as exc:
|
|
37
|
+
raise ValueError("ActorImageBinding.release_id must be a UUID string") from exc
|
|
38
|
+
object.__setattr__(self, "release_id", release_id)
|
|
33
39
|
for field_name in ("reason", "notes"):
|
|
34
40
|
value = getattr(self, field_name)
|
|
35
41
|
if value is not None and (not isinstance(value, str) or not value.strip()):
|
|
36
42
|
raise ValueError(
|
|
37
43
|
f"ActorImageBinding.{field_name} must be a nonempty string when set"
|
|
38
44
|
)
|
|
45
|
+
if value is not None:
|
|
46
|
+
object.__setattr__(self, field_name, value.strip())
|
|
39
47
|
|
|
40
48
|
def to_wire(self) -> dict[str, object]:
|
|
41
49
|
payload: dict[str, object] = {"release_id": self.release_id.strip()}
|
|
@@ -60,10 +68,14 @@ class ActorImageBinding:
|
|
|
60
68
|
raise ValueError("actor image binding release_id must be a string")
|
|
61
69
|
reason = payload.get("reason")
|
|
62
70
|
notes = payload.get("notes")
|
|
71
|
+
if reason is not None and not isinstance(reason, str):
|
|
72
|
+
raise ValueError("actor image binding reason must be a string when set")
|
|
73
|
+
if notes is not None and not isinstance(notes, str):
|
|
74
|
+
raise ValueError("actor image binding notes must be a string when set")
|
|
63
75
|
return cls(
|
|
64
76
|
release_id=release_id,
|
|
65
|
-
reason=reason
|
|
66
|
-
notes=notes
|
|
77
|
+
reason=reason,
|
|
78
|
+
notes=notes,
|
|
67
79
|
)
|
|
68
80
|
raise ValueError(
|
|
69
81
|
"actor image binding must be an ActorImageBinding, release id string, or mapping"
|
|
@@ -83,10 +95,14 @@ def actor_image_overrides_payload(
|
|
|
83
95
|
raise ValueError("actor_image_overrides must map actor roles to bindings")
|
|
84
96
|
payload: dict[str, dict[str, object]] = {}
|
|
85
97
|
for raw_role, raw_binding in overrides.items():
|
|
86
|
-
|
|
98
|
+
if not isinstance(raw_role, str):
|
|
99
|
+
raise ValueError("actor_image_overrides roles must be strings")
|
|
100
|
+
role = raw_role.strip().lower()
|
|
87
101
|
if role not in ACTOR_IMAGE_ROLES:
|
|
88
102
|
allowed = ", ".join(ACTOR_IMAGE_ROLES)
|
|
89
103
|
raise ValueError(f"actor_image_overrides role must be one of: {allowed}")
|
|
104
|
+
if role in payload:
|
|
105
|
+
raise ValueError(f"actor_image_overrides repeats role: {role}")
|
|
90
106
|
payload[role] = ActorImageBinding.from_wire(raw_binding).to_wire()
|
|
91
107
|
return payload or None
|
|
92
108
|
|
{synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/factories.py
RENAMED
|
@@ -550,7 +550,6 @@ class FactorySpec:
|
|
|
550
550
|
"name": self.name,
|
|
551
551
|
"kind": self.kind.value,
|
|
552
552
|
"status": self.state.value,
|
|
553
|
-
"result_authority_generation": self.result_authority_generation.value,
|
|
554
553
|
"budget_policy": self.budget.to_wire() if self.budget is not None else {},
|
|
555
554
|
"cap_policy": self.capacity.to_wire() if self.capacity is not None else {},
|
|
556
555
|
"homeostasis_policy": {},
|
|
@@ -558,6 +557,11 @@ class FactorySpec:
|
|
|
558
557
|
"authorization_policy": {},
|
|
559
558
|
"metadata": dict(self.metadata),
|
|
560
559
|
}
|
|
560
|
+
# Older production control planes predate this opt-in field and reject
|
|
561
|
+
# unknown keys. Legacy is the backend default, so only transmit an
|
|
562
|
+
# explicit non-legacy authority choice.
|
|
563
|
+
if self.result_authority_generation is not FactoryResultAuthorityGeneration.LEGACY:
|
|
564
|
+
value["result_authority_generation"] = self.result_authority_generation.value
|
|
561
565
|
if self.description is not None:
|
|
562
566
|
value["description"] = self.description
|
|
563
567
|
return value
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Public Managed Research failure vocabulary and wire contract."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from enum import StrEnum
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ActorFailureReason(StrEnum):
|
|
11
|
+
ACTOR_STARTUP_RETRY_BUDGET_EXHAUSTED = "actor_startup_retry_budget_exhausted"
|
|
12
|
+
TASK_BLOCKED = "task_blocked"
|
|
13
|
+
TASK_FAILED = "task_failed"
|
|
14
|
+
RUN_FAILED = "run_failed"
|
|
15
|
+
ORCHESTRATOR_SESSION_START_FAILED = "orchestrator_session_start_failed"
|
|
16
|
+
ORCHESTRATOR_SESSION_FAILED = "orchestrator_session_failed"
|
|
17
|
+
TASK_CLAIM_MATERIALIZATION_FAILED = "task_claim_materialization_failed"
|
|
18
|
+
CLAIMED_ACTOR_MISSING_TASK_BINDING = "claimed_actor_missing_task_binding"
|
|
19
|
+
WORKER_HOST_CLAIMED_NON_TASK_ACTOR = "worker_host_claimed_non_task_actor"
|
|
20
|
+
WORKER_HOST_ACTOR_RUN_MISSING = "worker_host_actor_run_missing"
|
|
21
|
+
WORKER_HOST_CLAIMED_ACTOR_TASK_MISSING = "worker_host_claimed_actor_task_missing"
|
|
22
|
+
TASK_ALREADY_TERMINAL = "task_already_terminal"
|
|
23
|
+
DB_POOL_PRESSURE = "db_pool_pressure"
|
|
24
|
+
CONTROL_PLANE_PRESSURE = "control_plane_pressure"
|
|
25
|
+
PARTICIPANT_START_BACKPRESSURE = "participant_start_backpressure"
|
|
26
|
+
PARTICIPANT_SYNC_DEFERRED_UNCONSUMED = "participant_sync_deferred_unconsumed"
|
|
27
|
+
TERMINAL_TRANSITION_DEFERRED_UNCONSUMED = "terminal_transition_deferred_unconsumed"
|
|
28
|
+
PARTICIPANT_LIVE_CAPACITY_EXHAUSTED = "participant_live_capacity_exhausted"
|
|
29
|
+
PARTICIPANT_MEMORY_CAPACITY_EXHAUSTED = "participant_memory_capacity_exhausted"
|
|
30
|
+
EXTERNAL_IO_DEFERRED = "external_io_deferred"
|
|
31
|
+
OPENCODE_ENDPOINT_UNREACHABLE = "opencode_endpoint_unreachable"
|
|
32
|
+
OPENCODE_ENDPOINT_REFUSED = "opencode_endpoint_refused"
|
|
33
|
+
OPENCODE_ENDPOINT_LOST = "opencode_endpoint_lost"
|
|
34
|
+
OPENCODE_ENDPOINT_HEALTH_TIMEOUT = "opencode_endpoint_health_timeout"
|
|
35
|
+
OPENCODE_CONTAINER_OOM = "opencode_container_oom"
|
|
36
|
+
OPENCODE_EVENT_STREAM_ROUTE_UNREACHABLE = "opencode_event_stream_route_unreachable"
|
|
37
|
+
OPENCODE_EVENT_STREAM_ENDPOINT_REFUSED = "opencode_event_stream_endpoint_refused"
|
|
38
|
+
OPENCODE_EVENT_STREAM_READ_TIMEOUT = "opencode_event_stream_read_timeout"
|
|
39
|
+
OPENCODE_EVENT_STREAM_URL_ERROR = "opencode_event_stream_url_error"
|
|
40
|
+
OPENCODE_EVENT_STREAM_RECONNECT_GRACE_EXHAUSTED = (
|
|
41
|
+
"opencode_event_stream_reconnect_grace_exhausted"
|
|
42
|
+
)
|
|
43
|
+
PARTICIPANT_SESSION_MISSING = "participant_session_missing"
|
|
44
|
+
PARTICIPANT_SESSION_START_FAILED = "participant_session_start_failed"
|
|
45
|
+
PARTICIPANT_LIVE_UNBOUND = "participant_live_unbound"
|
|
46
|
+
PARTICIPANT_LIVE_HANDLE_MISSING = "participant_live_handle_missing"
|
|
47
|
+
PARTICIPANT_BINDING_FAILED = "participant_binding_failed"
|
|
48
|
+
CLAIMED_TASK_WITHOUT_PARTICIPANT = "claimed_task_without_participant"
|
|
49
|
+
STALE_CLAIM_REAPED = "stale_claim_reaped"
|
|
50
|
+
RUNTIME_INTENT_BACKLOG = "runtime_intent_backlog"
|
|
51
|
+
UNKNOWN_UNHEALTHY_EXPIRED = "unknown_unhealthy_expired"
|
|
52
|
+
RUNTIME_NO_PRODUCTIVE_PROGRESS = "runtime_no_productive_progress"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ManagedResearchFailureFamily(StrEnum):
|
|
56
|
+
UNKNOWN = "unknown"
|
|
57
|
+
VALIDATION = "validation"
|
|
58
|
+
BOOTSTRAP = "bootstrap"
|
|
59
|
+
DISPATCH = "dispatch"
|
|
60
|
+
RUNTIME = "runtime"
|
|
61
|
+
RUNTIME_RECOVERY = "runtime_recovery"
|
|
62
|
+
TERMINALIZATION = "terminalization"
|
|
63
|
+
CLEANUP = "cleanup"
|
|
64
|
+
INFRASTRUCTURE = "infrastructure"
|
|
65
|
+
USAGE_CAPTURE = "usage_capture"
|
|
66
|
+
PARTICIPANT_START = "participant_start"
|
|
67
|
+
ORCHESTRATOR_CYCLE = "orchestrator_cycle"
|
|
68
|
+
ORCHESTRATOR_PROVIDER = "orchestrator_provider"
|
|
69
|
+
ORCHESTRATOR_CODEX = "orchestrator_codex"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ManagedResearchFailureSeverity(StrEnum):
|
|
73
|
+
WARNING = "warning"
|
|
74
|
+
ERROR = "error"
|
|
75
|
+
FATAL = "fatal"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ManagedResearchFailureScope(StrEnum):
|
|
79
|
+
ACTOR = "actor"
|
|
80
|
+
TASK = "task"
|
|
81
|
+
RUN = "run"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True)
|
|
85
|
+
class ManagedResearchFailureClassification:
|
|
86
|
+
family: ManagedResearchFailureFamily
|
|
87
|
+
code: str
|
|
88
|
+
severity: ManagedResearchFailureSeverity
|
|
89
|
+
retryable: bool
|
|
90
|
+
scope: ManagedResearchFailureScope | None = None
|
|
91
|
+
operator_action: str | None = None
|
|
92
|
+
detail: str | None = None
|
|
93
|
+
actor_id: str | None = None
|
|
94
|
+
actor_key: str | None = None
|
|
95
|
+
task_id: str | None = None
|
|
96
|
+
task_key: str | None = None
|
|
97
|
+
recorded_at: str | None = None
|
|
98
|
+
family_raw: str | None = None
|
|
99
|
+
raw: dict[str, Any] = field(default_factory=dict, repr=False, compare=False)
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def from_wire(cls, payload: object) -> ManagedResearchFailureClassification:
|
|
103
|
+
if not isinstance(payload, dict):
|
|
104
|
+
raise ValueError("run failure classification must be an object")
|
|
105
|
+
family = payload.get("family")
|
|
106
|
+
code = payload.get("code")
|
|
107
|
+
severity = payload.get("severity")
|
|
108
|
+
retryable = payload.get("retryable")
|
|
109
|
+
if not isinstance(family, str) or not isinstance(code, str):
|
|
110
|
+
raise ValueError("run failure classification requires family and code")
|
|
111
|
+
if not isinstance(severity, str) or not isinstance(retryable, bool):
|
|
112
|
+
raise ValueError("run failure classification requires severity and retryable")
|
|
113
|
+
try:
|
|
114
|
+
parsed_family = ManagedResearchFailureFamily(family)
|
|
115
|
+
except ValueError:
|
|
116
|
+
parsed_family = ManagedResearchFailureFamily.UNKNOWN
|
|
117
|
+
return cls(
|
|
118
|
+
family=parsed_family,
|
|
119
|
+
code=code,
|
|
120
|
+
severity=ManagedResearchFailureSeverity(severity),
|
|
121
|
+
retryable=retryable,
|
|
122
|
+
scope=(
|
|
123
|
+
ManagedResearchFailureScope(payload["scope"])
|
|
124
|
+
if isinstance(payload.get("scope"), str)
|
|
125
|
+
else None
|
|
126
|
+
),
|
|
127
|
+
operator_action=payload.get("operator_action")
|
|
128
|
+
if isinstance(payload.get("operator_action"), str)
|
|
129
|
+
else None,
|
|
130
|
+
detail=payload.get("detail") if isinstance(payload.get("detail"), str) else None,
|
|
131
|
+
actor_id=payload.get("actor_id") if isinstance(payload.get("actor_id"), str) else None,
|
|
132
|
+
actor_key=payload.get("actor_key")
|
|
133
|
+
if isinstance(payload.get("actor_key"), str)
|
|
134
|
+
else None,
|
|
135
|
+
task_id=payload.get("task_id") if isinstance(payload.get("task_id"), str) else None,
|
|
136
|
+
task_key=payload.get("task_key") if isinstance(payload.get("task_key"), str) else None,
|
|
137
|
+
recorded_at=payload.get("recorded_at")
|
|
138
|
+
if isinstance(payload.get("recorded_at"), str)
|
|
139
|
+
else None,
|
|
140
|
+
family_raw=family if parsed_family is ManagedResearchFailureFamily.UNKNOWN else None,
|
|
141
|
+
raw={str(key): value for key, value in payload.items()},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def to_wire(self) -> dict[str, Any]:
|
|
145
|
+
return {
|
|
146
|
+
key: value
|
|
147
|
+
for key, value in {
|
|
148
|
+
**self.raw,
|
|
149
|
+
"family": self.family.value,
|
|
150
|
+
"code": self.code,
|
|
151
|
+
"severity": self.severity.value,
|
|
152
|
+
"retryable": self.retryable,
|
|
153
|
+
"scope": self.scope.value if self.scope is not None else None,
|
|
154
|
+
"operator_action": self.operator_action,
|
|
155
|
+
"detail": self.detail,
|
|
156
|
+
"actor_id": self.actor_id,
|
|
157
|
+
"actor_key": self.actor_key,
|
|
158
|
+
"task_id": self.task_id,
|
|
159
|
+
"task_key": self.task_key,
|
|
160
|
+
"recorded_at": self.recorded_at,
|
|
161
|
+
"family_raw": self.family_raw,
|
|
162
|
+
}.items()
|
|
163
|
+
if value is not None
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
__all__ = [
|
|
168
|
+
"ActorFailureReason",
|
|
169
|
+
"ManagedResearchFailureClassification",
|
|
170
|
+
"ManagedResearchFailureFamily",
|
|
171
|
+
"ManagedResearchFailureScope",
|
|
172
|
+
"ManagedResearchFailureSeverity",
|
|
173
|
+
]
|
{synth_ai-0.18.0.dev590 → synth_ai-0.18.1.dev595}/synth_ai/sdk/research/contracts/image_releases.py
RENAMED
|
@@ -82,6 +82,26 @@ class ImageReleaseKind(StrEnum):
|
|
|
82
82
|
CRAFTAX_SCORER = "craftax_scorer"
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
class ActorImageCapability(StrEnum):
|
|
86
|
+
"""Capabilities admitted by the backend actor-runtime image contract."""
|
|
87
|
+
|
|
88
|
+
CODEX_CLI = "codex_cli"
|
|
89
|
+
CRAFTAX_EVAL = "craftax_eval"
|
|
90
|
+
CRAFTER_EVAL = "crafter_eval"
|
|
91
|
+
DUNGEONGRID_EVAL = "dungeongrid_eval"
|
|
92
|
+
IMAGE_ARTIFACTS = "image_artifacts"
|
|
93
|
+
JAX_CPU = "jax_cpu"
|
|
94
|
+
MANAGED_RESEARCH_SDK = "managed_research_sdk"
|
|
95
|
+
MCP_CLIENT = "mcp_client"
|
|
96
|
+
MODAL_CLIENT = "modal_client"
|
|
97
|
+
NETHACK_EVAL = "nethack_eval"
|
|
98
|
+
NUMPY_STACK = "numpy_stack"
|
|
99
|
+
OPENCODE = "opencode"
|
|
100
|
+
OPENROUTER_CLIENT = "openrouter_client"
|
|
101
|
+
SYNTH_SDK = "synth_sdk"
|
|
102
|
+
VIDEO_ARTIFACTS = "video_artifacts"
|
|
103
|
+
|
|
104
|
+
|
|
85
105
|
class RuntimeImageReleaseStatus(StrEnum):
|
|
86
106
|
ACTIVE = "active"
|
|
87
107
|
ARCHIVED = "archived"
|
|
@@ -149,6 +169,15 @@ def _strings(
|
|
|
149
169
|
return tuple(out)
|
|
150
170
|
|
|
151
171
|
|
|
172
|
+
def _capabilities(value: JsonValue) -> tuple[str, ...]:
|
|
173
|
+
capabilities = _strings(value, "capabilities", minimum=1)
|
|
174
|
+
allowed = frozenset(capability.value for capability in ActorImageCapability)
|
|
175
|
+
unexpected = sorted(set(capabilities) - allowed)
|
|
176
|
+
if unexpected:
|
|
177
|
+
raise ValueError(f"capabilities contain unsupported values: {unexpected!r}")
|
|
178
|
+
return capabilities
|
|
179
|
+
|
|
180
|
+
|
|
152
181
|
def _datetime(value: object, field: str) -> datetime:
|
|
153
182
|
parsed = (
|
|
154
183
|
value
|
|
@@ -260,7 +289,9 @@ class CraftaxScorerImageReleaseDeclaration(_DeclarationBase):
|
|
|
260
289
|
fixture_binary_sha256: str
|
|
261
290
|
|
|
262
291
|
def __post_init__(self) -> None:
|
|
263
|
-
|
|
292
|
+
# Explicit base dispatch is required for frozen slotted dataclasses on
|
|
293
|
+
# Python 3.12: zero-argument super() can retain the pre-slots class.
|
|
294
|
+
_DeclarationBase.__post_init__(self)
|
|
264
295
|
if self.kind is not ImageReleaseKind.CRAFTAX_SCORER:
|
|
265
296
|
raise ValueError("craftax scorer declaration kind must be craftax_scorer")
|
|
266
297
|
object.__setattr__(
|
|
@@ -304,7 +335,8 @@ class ActorRuntimeImageReleaseDeclaration(_DeclarationBase):
|
|
|
304
335
|
recipe_digest: str | None = None
|
|
305
336
|
|
|
306
337
|
def __post_init__(self) -> None:
|
|
307
|
-
|
|
338
|
+
# See CraftaxScorerImageReleaseDeclaration.__post_init__.
|
|
339
|
+
_DeclarationBase.__post_init__(self)
|
|
308
340
|
if self.kind is not ImageReleaseKind.ACTOR_RUNTIME:
|
|
309
341
|
raise ValueError("actor runtime declaration kind must be actor_runtime")
|
|
310
342
|
object.__setattr__(self, "actor_role", _const(self.actor_role, "actor_role", "worker"))
|
|
@@ -313,9 +345,7 @@ class ActorRuntimeImageReleaseDeclaration(_DeclarationBase):
|
|
|
313
345
|
"interface_mode",
|
|
314
346
|
_const(self.interface_mode, "interface_mode", "synth_actor_runtime"),
|
|
315
347
|
)
|
|
316
|
-
object.__setattr__(
|
|
317
|
-
self, "capabilities", _strings(list(self.capabilities), "capabilities", minimum=1)
|
|
318
|
-
)
|
|
348
|
+
object.__setattr__(self, "capabilities", _capabilities(list(self.capabilities)))
|
|
319
349
|
object.__setattr__(
|
|
320
350
|
self,
|
|
321
351
|
"python_packages",
|
|
@@ -439,7 +469,7 @@ def declaration_from_wire(value: JsonValue) -> ImageReleaseDeclaration:
|
|
|
439
469
|
source_commit_sha=source_commit_sha,
|
|
440
470
|
actor_role=_const(payload["actor_role"], "actor_role", "worker"),
|
|
441
471
|
interface_mode=_const(payload["interface_mode"], "interface_mode", "synth_actor_runtime"),
|
|
442
|
-
capabilities=
|
|
472
|
+
capabilities=_capabilities(payload["capabilities"]),
|
|
443
473
|
python_packages=_strings(payload["python_packages"], "python_packages", pattern=_PACKAGE),
|
|
444
474
|
recipe_digest=optional_digest(payload.get("recipe_digest"), field="recipe_digest"),
|
|
445
475
|
)
|
|
@@ -717,7 +747,7 @@ class ActorRuntimeImageMaterialization:
|
|
|
717
747
|
selection_kind=_const(
|
|
718
748
|
payload["selection_kind"], "selection_kind", "customer_actor_runtime"
|
|
719
749
|
),
|
|
720
|
-
capabilities=
|
|
750
|
+
capabilities=_capabilities(payload["capabilities"]),
|
|
721
751
|
python_packages=_strings(
|
|
722
752
|
payload["python_packages"], "python_packages", pattern=_PACKAGE
|
|
723
753
|
),
|
|
@@ -1199,6 +1229,7 @@ __all__ = [
|
|
|
1199
1229
|
"ActorRuntimeImageReleaseArchive",
|
|
1200
1230
|
"ActorRuntimeImageReleaseDeclaration",
|
|
1201
1231
|
"ActorRuntimeImageReleaseList",
|
|
1232
|
+
"ActorImageCapability",
|
|
1202
1233
|
"CraftaxScorerImageRelease",
|
|
1203
1234
|
"CraftaxScorerImageReleaseDeclaration",
|
|
1204
1235
|
"ImageRelease",
|
|
@@ -6,6 +6,7 @@ from collections.abc import Mapping
|
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from enum import StrEnum
|
|
8
8
|
|
|
9
|
+
from synth_ai.sdk.research.contracts.failure import ManagedResearchFailureClassification
|
|
9
10
|
from synth_ai.sdk.research.contracts.run_state import (
|
|
10
11
|
ManagedResearchRun,
|
|
11
12
|
ManagedResearchRunLivenessPhase,
|
|
@@ -1307,7 +1308,7 @@ class ManagedResearchRunContractIncidents:
|
|
|
1307
1308
|
class ManagedResearchRunContractDiagnostics:
|
|
1308
1309
|
lifecycle_invariants: list[dict[str, object]] = field(default_factory=list)
|
|
1309
1310
|
resource_wait: dict[str, object] | None = None
|
|
1310
|
-
failure_classification:
|
|
1311
|
+
failure_classification: ManagedResearchFailureClassification | None = None
|
|
1311
1312
|
|
|
1312
1313
|
@classmethod
|
|
1313
1314
|
def from_wire(cls, payload: object) -> ManagedResearchRunContractDiagnostics:
|
|
@@ -1327,10 +1328,12 @@ class ManagedResearchRunContractDiagnostics:
|
|
|
1327
1328
|
)
|
|
1328
1329
|
if resource_wait is not None
|
|
1329
1330
|
else None,
|
|
1330
|
-
failure_classification=
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1331
|
+
failure_classification=ManagedResearchFailureClassification.from_wire(
|
|
1332
|
+
dict(
|
|
1333
|
+
_require_mapping(
|
|
1334
|
+
failure_classification,
|
|
1335
|
+
label="run_contract.diagnostics.failure_classification",
|
|
1336
|
+
)
|
|
1334
1337
|
)
|
|
1335
1338
|
)
|
|
1336
1339
|
if failure_classification is not None
|
|
@@ -1509,6 +1512,7 @@ __all__ = [
|
|
|
1509
1512
|
"ManagedResearchRunContractArtifacts",
|
|
1510
1513
|
"ManagedResearchRunContractContainerEvalPackages",
|
|
1511
1514
|
"ManagedResearchRunContractDiagnostics",
|
|
1515
|
+
"ManagedResearchFailureClassification",
|
|
1512
1516
|
"ManagedResearchRunContractExecutionRoute",
|
|
1513
1517
|
"ManagedResearchRunContractFinalization",
|
|
1514
1518
|
"ManagedResearchRunContractIncidents",
|
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import hashlib
|
|
9
|
+
from pathlib import Path
|
|
8
10
|
from typing import cast
|
|
9
11
|
|
|
12
|
+
import httpx
|
|
13
|
+
|
|
10
14
|
from synth_ai.core.contracts.json_value import JsonObject, JsonValue
|
|
11
15
|
from synth_ai.core.http.async_transport import AsyncHttpTransport
|
|
12
16
|
from synth_ai.core.http.request import HttpRequest
|
|
@@ -79,6 +83,52 @@ def _retrieve(value: object, *, release_id: ImageReleaseId) -> ImageRelease:
|
|
|
79
83
|
return release
|
|
80
84
|
|
|
81
85
|
|
|
86
|
+
def _archive_path(
|
|
87
|
+
archive_path: str | Path,
|
|
88
|
+
*,
|
|
89
|
+
request: ImageReleaseUploadRequest,
|
|
90
|
+
) -> Path:
|
|
91
|
+
"""Verify the exact bytes that the backend will materialize.
|
|
92
|
+
|
|
93
|
+
The signed upload URL is intentionally the only direct-storage capability
|
|
94
|
+
used here. Authentication for the Research API is never forwarded to the
|
|
95
|
+
object store.
|
|
96
|
+
"""
|
|
97
|
+
path = Path(archive_path).expanduser().resolve()
|
|
98
|
+
if not path.is_file():
|
|
99
|
+
raise ValueError(f"image release archive is not a file: {path}")
|
|
100
|
+
if path.stat().st_size != request.declaration.archive_size_bytes:
|
|
101
|
+
raise ValueError("image release archive size does not match its declaration")
|
|
102
|
+
digest = hashlib.sha256()
|
|
103
|
+
with path.open("rb") as handle:
|
|
104
|
+
for block in iter(lambda: handle.read(1024 * 1024), b""):
|
|
105
|
+
digest.update(block)
|
|
106
|
+
if digest.hexdigest() != request.declaration.archive_sha256:
|
|
107
|
+
raise ValueError("image release archive digest does not match its declaration")
|
|
108
|
+
return path
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _upload_timeout_seconds(value: float) -> float:
|
|
112
|
+
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
|
113
|
+
raise ValueError("upload_timeout_seconds must be a number")
|
|
114
|
+
timeout_seconds = float(value)
|
|
115
|
+
if not 1.0 <= timeout_seconds <= 7200.0:
|
|
116
|
+
raise ValueError("upload_timeout_seconds must be between 1 and 7200")
|
|
117
|
+
return timeout_seconds
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _verify_finalized_upload(
|
|
121
|
+
finalized: ImageReleaseFinalize,
|
|
122
|
+
*,
|
|
123
|
+
upload: ImageReleaseUpload,
|
|
124
|
+
) -> ImageReleaseFinalize:
|
|
125
|
+
if finalized.release.release_id != upload.release_id:
|
|
126
|
+
raise ValueError("image finalize response changed its release identity")
|
|
127
|
+
if finalized.upload_reconciliation.upload_id != upload.upload_id:
|
|
128
|
+
raise ValueError("image finalize response changed its upload identity")
|
|
129
|
+
return finalized
|
|
130
|
+
|
|
131
|
+
|
|
82
132
|
class ImageReleasesAPI:
|
|
83
133
|
"""Immutable uploads plus executable actor-image materializations."""
|
|
84
134
|
|
|
@@ -115,6 +165,48 @@ class ImageReleasesAPI:
|
|
|
115
165
|
)
|
|
116
166
|
return _finalize(value, request=request)
|
|
117
167
|
|
|
168
|
+
def upload_archive(
|
|
169
|
+
self,
|
|
170
|
+
archive_path: str | Path,
|
|
171
|
+
request: ImageReleaseUploadRequest,
|
|
172
|
+
*,
|
|
173
|
+
upload_timeout_seconds: float = 1800.0,
|
|
174
|
+
) -> ImageReleaseFinalize:
|
|
175
|
+
"""Upload and materialize an exact declared OCI archive.
|
|
176
|
+
|
|
177
|
+
The local archive is validated before requesting a presigned URL. A
|
|
178
|
+
non-2xx object-store response is terminal: finalize is never attempted
|
|
179
|
+
against bytes the SDK did not observe as successfully uploaded.
|
|
180
|
+
"""
|
|
181
|
+
if not isinstance(request, ImageReleaseUploadRequest):
|
|
182
|
+
raise ValueError("request must be ImageReleaseUploadRequest")
|
|
183
|
+
path = _archive_path(archive_path, request=request)
|
|
184
|
+
timeout_seconds = _upload_timeout_seconds(upload_timeout_seconds)
|
|
185
|
+
upload = self.create_upload(request)
|
|
186
|
+
if upload.upload_required:
|
|
187
|
+
with (
|
|
188
|
+
httpx.Client(timeout=timeout_seconds, follow_redirects=False) as client,
|
|
189
|
+
path.open("rb") as archive,
|
|
190
|
+
):
|
|
191
|
+
response = client.put(
|
|
192
|
+
upload.upload_url,
|
|
193
|
+
content=archive,
|
|
194
|
+
headers={"Content-Length": str(request.declaration.archive_size_bytes)},
|
|
195
|
+
)
|
|
196
|
+
if not response.is_success:
|
|
197
|
+
raise RuntimeError(
|
|
198
|
+
f"image release archive upload failed with HTTP {response.status_code}"
|
|
199
|
+
)
|
|
200
|
+
return _verify_finalized_upload(
|
|
201
|
+
self.finalize(
|
|
202
|
+
ImageReleaseFinalizeRequest(
|
|
203
|
+
upload_id=upload.upload_id,
|
|
204
|
+
declaration=request.declaration,
|
|
205
|
+
)
|
|
206
|
+
),
|
|
207
|
+
upload=upload,
|
|
208
|
+
)
|
|
209
|
+
|
|
118
210
|
def list(self) -> ActorRuntimeImageReleaseList:
|
|
119
211
|
value = self._transport.execute(
|
|
120
212
|
_request(
|
|
@@ -147,6 +239,14 @@ class ImageReleasesAPI:
|
|
|
147
239
|
)
|
|
148
240
|
return _retrieve(value, release_id=release_id)
|
|
149
241
|
|
|
242
|
+
def get(self, release_id: ImageReleaseId) -> ImageRelease:
|
|
243
|
+
"""Retrieve one immutable image-release receipt.
|
|
244
|
+
|
|
245
|
+
``retrieve`` remains available for callers on the earlier core-client
|
|
246
|
+
surface; ``get`` matches the lifecycle verb used by the session API.
|
|
247
|
+
"""
|
|
248
|
+
return self.retrieve(release_id)
|
|
249
|
+
|
|
150
250
|
|
|
151
251
|
class AsyncImageReleasesAPI:
|
|
152
252
|
"""Native-async peer of :class:`ImageReleasesAPI`."""
|
|
@@ -184,6 +284,44 @@ class AsyncImageReleasesAPI:
|
|
|
184
284
|
)
|
|
185
285
|
return _finalize(value, request=request)
|
|
186
286
|
|
|
287
|
+
async def upload_archive(
|
|
288
|
+
self,
|
|
289
|
+
archive_path: str | Path,
|
|
290
|
+
request: ImageReleaseUploadRequest,
|
|
291
|
+
*,
|
|
292
|
+
upload_timeout_seconds: float = 1800.0,
|
|
293
|
+
) -> ImageReleaseFinalize:
|
|
294
|
+
"""Native-async upload and materialization of an exact OCI archive."""
|
|
295
|
+
if not isinstance(request, ImageReleaseUploadRequest):
|
|
296
|
+
raise ValueError("request must be ImageReleaseUploadRequest")
|
|
297
|
+
path = _archive_path(archive_path, request=request)
|
|
298
|
+
timeout_seconds = _upload_timeout_seconds(upload_timeout_seconds)
|
|
299
|
+
upload = await self.create_upload(request)
|
|
300
|
+
if upload.upload_required:
|
|
301
|
+
async with httpx.AsyncClient(
|
|
302
|
+
timeout=timeout_seconds,
|
|
303
|
+
follow_redirects=False,
|
|
304
|
+
) as client:
|
|
305
|
+
with path.open("rb") as archive:
|
|
306
|
+
response = await client.put(
|
|
307
|
+
upload.upload_url,
|
|
308
|
+
content=archive,
|
|
309
|
+
headers={"Content-Length": str(request.declaration.archive_size_bytes)},
|
|
310
|
+
)
|
|
311
|
+
if not response.is_success:
|
|
312
|
+
raise RuntimeError(
|
|
313
|
+
f"image release archive upload failed with HTTP {response.status_code}"
|
|
314
|
+
)
|
|
315
|
+
return _verify_finalized_upload(
|
|
316
|
+
await self.finalize(
|
|
317
|
+
ImageReleaseFinalizeRequest(
|
|
318
|
+
upload_id=upload.upload_id,
|
|
319
|
+
declaration=request.declaration,
|
|
320
|
+
)
|
|
321
|
+
),
|
|
322
|
+
upload=upload,
|
|
323
|
+
)
|
|
324
|
+
|
|
187
325
|
async def list(self) -> ActorRuntimeImageReleaseList:
|
|
188
326
|
value = await self._transport.execute(
|
|
189
327
|
_request(
|
|
@@ -216,5 +354,9 @@ class AsyncImageReleasesAPI:
|
|
|
216
354
|
)
|
|
217
355
|
return _retrieve(value, release_id=release_id)
|
|
218
356
|
|
|
357
|
+
async def get(self, release_id: ImageReleaseId) -> ImageRelease:
|
|
358
|
+
"""Native-async peer of :meth:`ImageReleasesAPI.get`."""
|
|
359
|
+
return await self.retrieve(release_id)
|
|
360
|
+
|
|
219
361
|
|
|
220
362
|
__all__ = ["AsyncImageReleasesAPI", "ImageReleasesAPI"]
|