synth-ai 0.18.2.dev614__tar.gz → 0.18.2.dev617__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.
Files changed (260) hide show
  1. {synth_ai-0.18.2.dev614/synth_ai.egg-info → synth_ai-0.18.2.dev617}/PKG-INFO +2 -4
  2. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/README.md +1 -3
  3. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/pyproject.toml +1 -1
  4. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/__init__.py +22 -0
  5. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/client.py +38 -3
  6. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/research_intern.py +5 -0
  7. synth_ai-0.18.2.dev617/synth_ai/sdk/optimizers/__init__.py +30 -0
  8. synth_ai-0.18.2.dev617/synth_ai/sdk/optimizers/client.py +309 -0
  9. synth_ai-0.18.2.dev617/synth_ai/sdk/optimizers/contracts.py +142 -0
  10. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/__init__.py +12 -0
  11. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/research_intern.py +67 -0
  12. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_launch.py +15 -1
  13. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/traces.py +48 -1
  14. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/errors.py +65 -0
  15. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/operations.py +335 -4
  16. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/public.py +34 -0
  17. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/research_intern.py +184 -0
  18. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/_client_helpers.py +55 -0
  19. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/client.py +32 -55
  20. synth_ai-0.18.2.dev617/synth_ai/sdk/research/surface_parity.py +189 -0
  21. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/traces.py +47 -0
  22. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/transport/http.py +15 -0
  23. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617/synth_ai.egg-info}/PKG-INFO +2 -4
  24. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai.egg-info/SOURCES.txt +4 -0
  25. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/LICENSE +0 -0
  26. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/MANIFEST.in +0 -0
  27. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/setup.cfg +0 -0
  28. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/README.md +0 -0
  29. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/__main__.py +0 -0
  30. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/AGENTS.md +0 -0
  31. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/README.md +0 -0
  32. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/__init__.py +0 -0
  33. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/__main__.py +0 -0
  34. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/main.py +0 -0
  35. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/research.py +0 -0
  36. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/research_environments.py +0 -0
  37. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/research_image_releases.py +0 -0
  38. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/cli/research_projects.py +0 -0
  39. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/README.md +0 -0
  40. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/__init__.py +0 -0
  41. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/auth/__init__.py +0 -0
  42. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/auth/credentials.py +0 -0
  43. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/contracts/__init__.py +0 -0
  44. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/contracts/json_value.py +0 -0
  45. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/contracts/pagination.py +0 -0
  46. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/errors.py +0 -0
  47. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/http/__init__.py +0 -0
  48. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/http/async_transport.py +0 -0
  49. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/http/request.py +0 -0
  50. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/http/retry.py +0 -0
  51. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/http/streaming.py +0 -0
  52. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/http/transport.py +0 -0
  53. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/research/__init__.py +0 -0
  54. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/utils/__init__.py +0 -0
  55. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/utils/env.py +0 -0
  56. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/utils/log_filter.py +0 -0
  57. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/utils/paths.py +0 -0
  58. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/core/utils/urls.py +0 -0
  59. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/README.md +0 -0
  60. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/__init__.py +0 -0
  61. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/__main__.py +0 -0
  62. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/objective_tools.py +0 -0
  63. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/registry.py +0 -0
  64. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/request_models.py +0 -0
  65. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/server.py +0 -0
  66. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/__init__.py +0 -0
  67. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/approvals.py +0 -0
  68. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/artifacts.py +0 -0
  69. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/datasets.py +0 -0
  70. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/environments.py +0 -0
  71. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/exports.py +0 -0
  72. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/factories.py +0 -0
  73. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/factory_results.py +0 -0
  74. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/files.py +0 -0
  75. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/image_releases.py +0 -0
  76. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/integrations.py +0 -0
  77. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/intern_program.py +0 -0
  78. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/logs.py +0 -0
  79. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/models.py +0 -0
  80. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/outputs.py +0 -0
  81. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/policy_schemas.py +0 -0
  82. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/progress.py +0 -0
  83. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/project_data.py +0 -0
  84. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/projects.py +0 -0
  85. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/prs.py +0 -0
  86. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/readiness.py +0 -0
  87. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/repos.py +0 -0
  88. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/resources.py +0 -0
  89. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/runs.py +0 -0
  90. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/trained_models.py +0 -0
  91. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/usage.py +0 -0
  92. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/visuals.py +0 -0
  93. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/mcp/research/tools/workspace_inputs.py +0 -0
  94. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/py.typed +0 -0
  95. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/README.md +0 -0
  96. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/__init__.py +0 -0
  97. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/pagination.py +0 -0
  98. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/__init__.py +0 -0
  99. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/_internal/__init__.py +0 -0
  100. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/_internal/crypto.py +0 -0
  101. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/_internal/env.py +0 -0
  102. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/_internal/urls.py +0 -0
  103. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/account.py +0 -0
  104. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/advanced.py +0 -0
  105. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/advanced_factories.py +0 -0
  106. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/advanced_swarms.py +0 -0
  107. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/artifacts.py +0 -0
  108. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/auth.py +0 -0
  109. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/client.py +0 -0
  110. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/_activity_wire.py +0 -0
  111. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/_environment_wire.py +0 -0
  112. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/_transcript_wire.py +0 -0
  113. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/_wire.py +0 -0
  114. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/activity.py +0 -0
  115. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/activity_items.py +0 -0
  116. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/actor_images.py +0 -0
  117. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/billing.py +0 -0
  118. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/canonical_usage.py +0 -0
  119. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/checkpoints.py +0 -0
  120. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/cloud_deployment_claims.py +0 -0
  121. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/cloud_deployments.py +0 -0
  122. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/common.py +0 -0
  123. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/dataset_revisions.py +0 -0
  124. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/deliveries.py +0 -0
  125. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/dev_environment_evidence.py +0 -0
  126. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/economics.py +0 -0
  127. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/environment_manifest.py +0 -0
  128. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/environments.py +0 -0
  129. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/evidence.py +0 -0
  130. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/factories.py +0 -0
  131. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/factory_evidence.py +0 -0
  132. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/factory_lenses.py +0 -0
  133. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/factory_operations.py +0 -0
  134. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/factory_role_receipts.py +0 -0
  135. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/failure.py +0 -0
  136. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/image_releases.py +0 -0
  137. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/intern_grants.py +0 -0
  138. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/intern_program.py +0 -0
  139. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/limit_evidence.py +0 -0
  140. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/local_execution_profile.py +0 -0
  141. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/operator_evidence.py +0 -0
  142. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/project.py +0 -0
  143. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/project_data.py +0 -0
  144. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/project_runtime.py +0 -0
  145. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/project_workspace.py +0 -0
  146. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/project_workspace_evidence.py +0 -0
  147. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/projects.py +0 -0
  148. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/promotions.py +0 -0
  149. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_authority.py +0 -0
  150. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_control.py +0 -0
  151. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_diagnostics.py +0 -0
  152. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_events.py +0 -0
  153. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_execution.py +0 -0
  154. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_observability.py +0 -0
  155. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_state.py +0 -0
  156. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/run_timeline.py +0 -0
  157. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/runtime_image.py +0 -0
  158. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/runtime_intent.py +0 -0
  159. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/runtime_stream.py +0 -0
  160. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/runtime_stream_snapshot.py +0 -0
  161. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/scientific_integrity.py +0 -0
  162. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_actor_models.py +0 -0
  163. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_actor_policy_data.py +0 -0
  164. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_agent_harnesses.py +0 -0
  165. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_agent_kinds.py +0 -0
  166. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_agent_models.py +0 -0
  167. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_branching.py +0 -0
  168. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_credential_providers.py +0 -0
  169. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_environment_kinds.py +0 -0
  170. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_evidence_obligations.py +0 -0
  171. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_funding_sources.py +0 -0
  172. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_horizons.py +0 -0
  173. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_host_kinds.py +0 -0
  174. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_inference_providers.py +0 -0
  175. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_network_topology.py +0 -0
  176. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_providers.py +0 -0
  177. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_resource_kinds.py +0 -0
  178. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_roles.py +0 -0
  179. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_run_policy.py +0 -0
  180. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_runbooks.py +0 -0
  181. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_runnable_project.py +0 -0
  182. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_runtime_kinds.py +0 -0
  183. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_tool_providers.py +0 -0
  184. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/smr_work_modes.py +0 -0
  185. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/status.py +0 -0
  186. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/swarms.py +0 -0
  187. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/tag.py +0 -0
  188. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/transcript.py +0 -0
  189. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/types.py +0 -0
  190. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/usage.py +0 -0
  191. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/visuals.py +0 -0
  192. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/wire_models.py +0 -0
  193. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/wire_models_README.md +0 -0
  194. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/work_products.py +0 -0
  195. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/contracts/workspaces.py +0 -0
  196. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/economics.py +0 -0
  197. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/efforts.py +0 -0
  198. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/environments.py +0 -0
  199. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/events.py +0 -0
  200. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/experiments.py +0 -0
  201. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/facade.py +0 -0
  202. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/factories.py +0 -0
  203. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/factory_storage.py +0 -0
  204. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/image_releases.py +0 -0
  205. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/intern_program.py +0 -0
  206. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/knowledge.py +0 -0
  207. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/models.py +0 -0
  208. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/project_data.py +0 -0
  209. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/project_deliveries.py +0 -0
  210. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/project_workspaces.py +0 -0
  211. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/projects.py +0 -0
  212. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/readouts.py +0 -0
  213. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/secrets.py +0 -0
  214. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/README.md +0 -0
  215. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/__init__.py +0 -0
  216. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/_base.py +0 -0
  217. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/_run_authority_mixin.py +0 -0
  218. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/approvals.py +0 -0
  219. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/billing.py +0 -0
  220. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/cloud_deployments.py +0 -0
  221. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/config.py +0 -0
  222. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/cost.py +0 -0
  223. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/datasets.py +0 -0
  224. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/dev_environments.py +0 -0
  225. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/environments.py +0 -0
  226. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/exports.py +0 -0
  227. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/factories.py +0 -0
  228. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/factory_evidence.py +0 -0
  229. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/files.py +0 -0
  230. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/github.py +0 -0
  231. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/image_releases.py +0 -0
  232. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/images.py +0 -0
  233. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/logs.py +0 -0
  234. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/models.py +0 -0
  235. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/outputs.py +0 -0
  236. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/progress.py +0 -0
  237. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/project.py +0 -0
  238. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/projects.py +0 -0
  239. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/prs.py +0 -0
  240. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/readiness.py +0 -0
  241. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/repositories.py +0 -0
  242. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/runs.py +0 -0
  243. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/secrets.py +0 -0
  244. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/setup.py +0 -0
  245. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/tag.py +0 -0
  246. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/trained_models.py +0 -0
  247. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/transport.py +0 -0
  248. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/usage.py +0 -0
  249. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/work_products.py +0 -0
  250. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/session/workspace_inputs.py +0 -0
  251. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/swarms.py +0 -0
  252. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/transport/__init__.py +0 -0
  253. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/transport/pagination.py +0 -0
  254. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/version.py +0 -0
  255. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/visuals.py +0 -0
  256. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai/sdk/research/wiki.py +0 -0
  257. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai.egg-info/dependency_links.txt +0 -0
  258. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai.egg-info/entry_points.txt +0 -0
  259. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/synth_ai.egg-info/requires.txt +0 -0
  260. {synth_ai-0.18.2.dev614 → synth_ai-0.18.2.dev617}/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.2.dev614
3
+ Version: 0.18.2.dev617
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
@@ -145,9 +145,7 @@ from synth_ai import SynthClient
145
145
  from synth_ai.sdk.research.public import EffortSpec, FactorySpec, ProjectId
146
146
 
147
147
  with SynthClient() as client:
148
- factory = client.research.factories.create(
149
- FactorySpec(name="Prompt optimizer")
150
- )
148
+ factory = client.research.factories.create(FactorySpec(name="Prompt optimizer"))
151
149
  effort = client.research.factories.efforts.create(
152
150
  EffortSpec(
153
151
  factory_id=factory.factory_id,
@@ -118,9 +118,7 @@ from synth_ai import SynthClient
118
118
  from synth_ai.sdk.research.public import EffortSpec, FactorySpec, ProjectId
119
119
 
120
120
  with SynthClient() as client:
121
- factory = client.research.factories.create(
122
- FactorySpec(name="Prompt optimizer")
123
- )
121
+ factory = client.research.factories.create(FactorySpec(name="Prompt optimizer"))
124
122
  effort = client.research.factories.efforts.create(
125
123
  EffortSpec(
126
124
  factory_id=factory.factory_id,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "synth-ai"
3
- version = "0.18.2.dev614"
3
+ version = "0.18.2.dev617"
4
4
  description = "Python SDK and CLI for Synth Managed Research and Research Factory"
5
5
  authors = [{name = "Synth AI", email = "josh@usesynth.ai"}]
6
6
  license = "MIT"
@@ -39,6 +39,7 @@ except _PackageNotFoundError:
39
39
  __all__ = [
40
40
  "AsyncResearchInternReactiveSession",
41
41
  "AsyncSynthClient",
42
+ "AsyncOptimizersClient",
42
43
  "DataBindingCreateRequest",
43
44
  "DatasetRevisionCreateRequest",
44
45
  "DatasetRevisionFinalizeRequest",
@@ -99,9 +100,30 @@ __all__ = [
99
100
  "ResearchVisualPromotionRequest",
100
101
  "ResearchVisualVersions",
101
102
  "SynthClient",
103
+ "OptimizersClient",
104
+ "OptimizerRunOutputs",
105
+ "SavedLoraCheckpoint",
106
+ "SavedLoraCheckpointPage",
107
+ "SavedLoraLineage",
108
+ "SavedLoraRunPage",
109
+ "HostedTrainingModelCatalog",
102
110
  ]
103
111
 
104
112
  _EXPORTS: dict[str, tuple[str, str]] = {
113
+ "AsyncOptimizersClient": ("synth_ai.sdk.optimizers", "AsyncOptimizersClient"),
114
+ "HostedTrainingModelCatalog": (
115
+ "synth_ai.sdk.optimizers",
116
+ "HostedTrainingModelCatalog",
117
+ ),
118
+ "OptimizersClient": ("synth_ai.sdk.optimizers", "OptimizersClient"),
119
+ "OptimizerRunOutputs": ("synth_ai.sdk.optimizers", "OptimizerRunOutputs"),
120
+ "SavedLoraCheckpoint": ("synth_ai.sdk.optimizers", "SavedLoraCheckpoint"),
121
+ "SavedLoraCheckpointPage": (
122
+ "synth_ai.sdk.optimizers",
123
+ "SavedLoraCheckpointPage",
124
+ ),
125
+ "SavedLoraLineage": ("synth_ai.sdk.optimizers", "SavedLoraLineage"),
126
+ "SavedLoraRunPage": ("synth_ai.sdk.optimizers", "SavedLoraRunPage"),
105
127
  "AsyncResearchInternReactiveSession": (
106
128
  "synth_ai.sdk.research.research_intern",
107
129
  "AsyncResearchInternReactiveSession",
@@ -9,6 +9,7 @@ from synth_ai.core.auth.credentials import resolve_api_credential
9
9
  from synth_ai.core.utils.urls import BACKEND_URL_BASE, normalize_backend_base
10
10
 
11
11
  if TYPE_CHECKING:
12
+ from synth_ai.sdk.optimizers import AsyncOptimizersClient, OptimizersClient
12
13
  from synth_ai.sdk.research import AsyncResearchClient
13
14
  from synth_ai.sdk.research.facade import ResearchClient
14
15
 
@@ -22,10 +23,10 @@ def _resolve_base_url(base_url: str | None) -> str:
22
23
 
23
24
 
24
25
  class SynthClient:
25
- """Sync client for Managed Research.
26
+ """Sync client for Managed Research and hosted optimizers.
26
27
 
27
28
  Use ``research`` for hosted projects, swarms, and Factory lifecycles. That
28
- is the whole client: there is no container, tunnel, or pool namespace.
29
+ Use ``optimizers`` for hosted training model discovery and saved LoRAs.
29
30
  """
30
31
 
31
32
  def __init__(
@@ -41,6 +42,7 @@ class SynthClient:
41
42
  self.timeout_seconds = timeout_seconds
42
43
  self.allow_legacy_intern_sessions = allow_legacy_intern_sessions
43
44
  self._research_client: ResearchClient | None = None
45
+ self._optimizers_client: OptimizersClient | None = None
44
46
 
45
47
  @property
46
48
  def research(self) -> ResearchClient:
@@ -61,6 +63,22 @@ class SynthClient:
61
63
  if self._research_client is not None:
62
64
  self._research_client.close()
63
65
  self._research_client = None
66
+ if self._optimizers_client is not None:
67
+ self._optimizers_client.close()
68
+ self._optimizers_client = None
69
+
70
+ @property
71
+ def optimizers(self) -> OptimizersClient:
72
+ """Hosted training models and searchable saved-LoRA lineage."""
73
+ if self._optimizers_client is None:
74
+ from synth_ai.sdk.optimizers import OptimizersClient
75
+
76
+ self._optimizers_client = OptimizersClient(
77
+ api_key=self.api_key,
78
+ base_url=self.base_url,
79
+ timeout_seconds=self.timeout_seconds,
80
+ )
81
+ return self._optimizers_client
64
82
 
65
83
  def __enter__(self) -> SynthClient:
66
84
  return self
@@ -70,7 +88,7 @@ class SynthClient:
70
88
 
71
89
 
72
90
  class AsyncSynthClient:
73
- """Async client for Managed Research."""
91
+ """Async client for Managed Research and hosted optimizers."""
74
92
 
75
93
  def __init__(
76
94
  self,
@@ -85,6 +103,7 @@ class AsyncSynthClient:
85
103
  self.timeout_seconds = timeout_seconds
86
104
  self.allow_legacy_intern_sessions = allow_legacy_intern_sessions
87
105
  self._async_research_client: AsyncResearchClient | None = None
106
+ self._async_optimizers_client: AsyncOptimizersClient | None = None
88
107
 
89
108
  @property
90
109
  def research(self) -> AsyncResearchClient:
@@ -115,6 +134,22 @@ class AsyncSynthClient:
115
134
  if self._async_research_client is not None:
116
135
  await self._async_research_client.close()
117
136
  self._async_research_client = None
137
+ if self._async_optimizers_client is not None:
138
+ await self._async_optimizers_client.close()
139
+ self._async_optimizers_client = None
140
+
141
+ @property
142
+ def optimizers(self) -> AsyncOptimizersClient:
143
+ """Native asynchronous hosted optimizer namespace."""
144
+ if self._async_optimizers_client is None:
145
+ from synth_ai.sdk.optimizers import AsyncOptimizersClient
146
+
147
+ self._async_optimizers_client = AsyncOptimizersClient(
148
+ api_key=self.api_key,
149
+ base_url=self.base_url,
150
+ timeout_seconds=self.timeout_seconds,
151
+ )
152
+ return self._async_optimizers_client
118
153
 
119
154
  async def __aenter__(self) -> AsyncSynthClient:
120
155
  return self
@@ -1153,6 +1153,11 @@ def build_research_intern_tools(
1153
1153
  "type": "integer",
1154
1154
  "minimum": 0,
1155
1155
  "maximum": 60,
1156
+ "description": (
1157
+ "Bounded wait for the explicit Factory-ready "
1158
+ "condition before binding; omit to refuse "
1159
+ "immediately with a typed readiness report."
1160
+ ),
1156
1161
  },
1157
1162
  },
1158
1163
  required=["objective", "idempotency_key"],
@@ -0,0 +1,30 @@
1
+ """Public hosted optimizer SDK namespace."""
2
+
3
+ from synth_ai.sdk.optimizers.client import AsyncOptimizersClient, OptimizersClient
4
+ from synth_ai.sdk.optimizers.contracts import (
5
+ HostedTrainingModel,
6
+ HostedTrainingModelCatalog,
7
+ OptimizerRunArtifact,
8
+ OptimizerRunIdentity,
9
+ OptimizerRunOutputs,
10
+ SavedLoraCheckpoint,
11
+ SavedLoraCheckpointPage,
12
+ SavedLoraLineage,
13
+ SavedLoraRunPage,
14
+ SavedLoraStorage,
15
+ )
16
+
17
+ __all__ = [
18
+ "AsyncOptimizersClient",
19
+ "HostedTrainingModel",
20
+ "HostedTrainingModelCatalog",
21
+ "OptimizerRunIdentity",
22
+ "OptimizerRunArtifact",
23
+ "OptimizerRunOutputs",
24
+ "OptimizersClient",
25
+ "SavedLoraCheckpoint",
26
+ "SavedLoraCheckpointPage",
27
+ "SavedLoraLineage",
28
+ "SavedLoraRunPage",
29
+ "SavedLoraStorage",
30
+ ]
@@ -0,0 +1,309 @@
1
+ """Public sync and async clients for hosted optimizers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+ from typing import Any
7
+ from urllib.parse import quote
8
+
9
+ from synth_ai.core.auth.credentials import resolve_api_credential
10
+ from synth_ai.core.contracts.json_value import JsonObject, JsonValue
11
+ from synth_ai.core.http.async_transport import AsyncHttpTransport
12
+ from synth_ai.core.http.transport import HttpTransport
13
+ from synth_ai.core.utils.urls import BACKEND_URL_BASE, normalize_backend_base
14
+ from synth_ai.sdk.optimizers.contracts import (
15
+ HostedTrainingModelCatalog,
16
+ OptimizerRunOutputs,
17
+ SavedLoraCheckpoint,
18
+ SavedLoraCheckpointPage,
19
+ SavedLoraRunPage,
20
+ )
21
+
22
+
23
+ def _object(payload: JsonValue) -> JsonObject:
24
+ if not isinstance(payload, dict):
25
+ raise ValueError("optimizer API response must be an object")
26
+ return payload
27
+
28
+
29
+ def _params(**values: Any) -> dict[str, JsonValue]:
30
+ return {key: value for key, value in values.items() if value is not None and value != ""}
31
+
32
+
33
+ class CheckpointsAPI:
34
+ """List automatically persisted checkpoints and traverse their lineage."""
35
+
36
+ def __init__(self, transport: HttpTransport) -> None:
37
+ self._transport = transport
38
+
39
+ def list(
40
+ self,
41
+ *,
42
+ query: str | None = None,
43
+ scope: str = "all",
44
+ optimizer_algorithm: str | None = None,
45
+ run_id: str | None = None,
46
+ attempt_id: str | None = None,
47
+ source_checkpoint_id: str | None = None,
48
+ provider: str | None = None,
49
+ checkpoint_kind: str | None = None,
50
+ base_model: str | None = None,
51
+ status: str | None = "ready",
52
+ tags: Sequence[str] | None = None,
53
+ limit: int = 50,
54
+ offset: int = 0,
55
+ ) -> SavedLoraCheckpointPage:
56
+ """Search saved checkpoints with filters and a page size clamped to 1–100."""
57
+ payload = self._transport.request_json(
58
+ "GET",
59
+ "/api/v1/optimizers/checkpoints",
60
+ params=_params(
61
+ q=query,
62
+ scope=scope,
63
+ optimizer_algorithm=optimizer_algorithm,
64
+ run_id=run_id,
65
+ attempt_id=attempt_id,
66
+ source_checkpoint_id=source_checkpoint_id,
67
+ provider=provider,
68
+ checkpoint_kind=checkpoint_kind,
69
+ base_model=base_model,
70
+ status=status,
71
+ tags=tags,
72
+ limit=max(1, min(100, limit)),
73
+ offset=max(0, offset),
74
+ ),
75
+ operation_id="optimizers.checkpoints.list",
76
+ )
77
+ return SavedLoraCheckpointPage.model_validate(_object(payload))
78
+
79
+ def get(self, checkpoint_id: str) -> SavedLoraCheckpoint:
80
+ """Retrieve one saved checkpoint by its URL-escaped identifier."""
81
+ payload = self._transport.request_json(
82
+ "GET",
83
+ f"/api/v1/optimizers/checkpoints/{quote(checkpoint_id, safe='')}",
84
+ operation_id="optimizers.checkpoints.get",
85
+ )
86
+ return SavedLoraCheckpoint.model_validate(_object(payload))
87
+
88
+ def list_for_run(
89
+ self,
90
+ run_id: str,
91
+ *,
92
+ checkpoint_kind: str | None = None,
93
+ status: str | None = "ready",
94
+ limit: int = 100,
95
+ offset: int = 0,
96
+ ) -> SavedLoraRunPage:
97
+ """List saved checkpoints for one run with bounded pagination."""
98
+ payload = self._transport.request_json(
99
+ "GET",
100
+ f"/api/v1/optimizers/runs/{quote(run_id, safe='')}/saved-checkpoints",
101
+ params=_params(
102
+ checkpoint_kind=checkpoint_kind,
103
+ status=status,
104
+ limit=max(1, min(100, limit)),
105
+ offset=max(0, offset),
106
+ ),
107
+ operation_id="optimizers.checkpoints.list_for_run",
108
+ )
109
+ return SavedLoraRunPage.model_validate(_object(payload))
110
+
111
+
112
+ class ModelsAPI:
113
+ """Discover models and algorithm support available for hosted training."""
114
+
115
+ def __init__(self, transport: HttpTransport) -> None:
116
+ self._transport = transport
117
+
118
+ def list(
119
+ self, *, algorithm: str | None = None, provider: str | None = None
120
+ ) -> HostedTrainingModelCatalog:
121
+ """Discover hosted training models filtered by algorithm and provider."""
122
+ payload = self._transport.request_json(
123
+ "GET",
124
+ "/api/v1/optimizers/models/training",
125
+ params=_params(algorithm=algorithm, provider=provider),
126
+ operation_id="optimizers.models.list",
127
+ )
128
+ return HostedTrainingModelCatalog.model_validate(_object(payload))
129
+
130
+
131
+ class RunsAPI:
132
+ """Inspect automatically persisted outputs for hosted optimizer runs."""
133
+
134
+ def __init__(self, transport: HttpTransport) -> None:
135
+ self._transport = transport
136
+
137
+ def outputs(self, run_id: str) -> OptimizerRunOutputs:
138
+ """Retrieve the backend-owned output inventory for one optimizer run."""
139
+ payload = self._transport.request_json(
140
+ "GET",
141
+ f"/api/v1/optimizers/runs/{quote(run_id, safe='')}/outputs",
142
+ operation_id="optimizers.runs.outputs",
143
+ )
144
+ return OptimizerRunOutputs.model_validate(_object(payload))
145
+
146
+
147
+ class AsyncCheckpointsAPI:
148
+ """Asynchronous saved-checkpoint discovery and lineage reads."""
149
+
150
+ def __init__(self, transport: AsyncHttpTransport) -> None:
151
+ self._transport = transport
152
+
153
+ async def list(
154
+ self,
155
+ *,
156
+ query: str | None = None,
157
+ scope: str = "all",
158
+ optimizer_algorithm: str | None = None,
159
+ run_id: str | None = None,
160
+ attempt_id: str | None = None,
161
+ source_checkpoint_id: str | None = None,
162
+ provider: str | None = None,
163
+ checkpoint_kind: str | None = None,
164
+ base_model: str | None = None,
165
+ status: str | None = "ready",
166
+ tags: Sequence[str] | None = None,
167
+ limit: int = 50,
168
+ offset: int = 0,
169
+ ) -> SavedLoraCheckpointPage:
170
+ """Search saved checkpoints with filters and a page size clamped to 1–100."""
171
+ payload = await self._transport.request_json(
172
+ "GET",
173
+ "/api/v1/optimizers/checkpoints",
174
+ params=_params(
175
+ q=query,
176
+ scope=scope,
177
+ optimizer_algorithm=optimizer_algorithm,
178
+ run_id=run_id,
179
+ attempt_id=attempt_id,
180
+ source_checkpoint_id=source_checkpoint_id,
181
+ provider=provider,
182
+ checkpoint_kind=checkpoint_kind,
183
+ base_model=base_model,
184
+ status=status,
185
+ tags=tags,
186
+ limit=max(1, min(100, limit)),
187
+ offset=max(0, offset),
188
+ ),
189
+ operation_id="optimizers.checkpoints.list",
190
+ )
191
+ return SavedLoraCheckpointPage.model_validate(_object(payload))
192
+
193
+ async def get(self, checkpoint_id: str) -> SavedLoraCheckpoint:
194
+ """Retrieve one saved checkpoint by its URL-escaped identifier."""
195
+ payload = await self._transport.request_json(
196
+ "GET",
197
+ f"/api/v1/optimizers/checkpoints/{quote(checkpoint_id, safe='')}",
198
+ operation_id="optimizers.checkpoints.get",
199
+ )
200
+ return SavedLoraCheckpoint.model_validate(_object(payload))
201
+
202
+ async def list_for_run(
203
+ self,
204
+ run_id: str,
205
+ *,
206
+ checkpoint_kind: str | None = None,
207
+ status: str | None = "ready",
208
+ limit: int = 100,
209
+ offset: int = 0,
210
+ ) -> SavedLoraRunPage:
211
+ """List saved checkpoints for one run with bounded pagination."""
212
+ payload = await self._transport.request_json(
213
+ "GET",
214
+ f"/api/v1/optimizers/runs/{quote(run_id, safe='')}/saved-checkpoints",
215
+ params=_params(
216
+ checkpoint_kind=checkpoint_kind,
217
+ status=status,
218
+ limit=max(1, min(100, limit)),
219
+ offset=max(0, offset),
220
+ ),
221
+ operation_id="optimizers.checkpoints.list_for_run",
222
+ )
223
+ return SavedLoraRunPage.model_validate(_object(payload))
224
+
225
+
226
+ class AsyncModelsAPI:
227
+ """Asynchronous hosted training model discovery."""
228
+
229
+ def __init__(self, transport: AsyncHttpTransport) -> None:
230
+ self._transport = transport
231
+
232
+ async def list(self, **filters: Any) -> HostedTrainingModelCatalog:
233
+ """Read the training model catalog using backend-supported query filters."""
234
+ payload = await self._transport.request_json(
235
+ "GET",
236
+ "/api/v1/optimizers/models/training",
237
+ params=_params(**filters),
238
+ operation_id="optimizers.models.list",
239
+ )
240
+ return HostedTrainingModelCatalog.model_validate(_object(payload))
241
+
242
+
243
+ class AsyncRunsAPI:
244
+ """Asynchronous reads of persisted hosted optimizer outputs."""
245
+
246
+ def __init__(self, transport: AsyncHttpTransport) -> None:
247
+ self._transport = transport
248
+
249
+ async def outputs(self, run_id: str) -> OptimizerRunOutputs:
250
+ """Retrieve the backend-owned output inventory for one optimizer run."""
251
+ payload = await self._transport.request_json(
252
+ "GET",
253
+ f"/api/v1/optimizers/runs/{quote(run_id, safe='')}/outputs",
254
+ operation_id="optimizers.runs.outputs",
255
+ )
256
+ return OptimizerRunOutputs.model_validate(_object(payload))
257
+
258
+
259
+ class OptimizersClient:
260
+ """Hosted optimizer namespace mounted at ``SynthClient.optimizers``."""
261
+
262
+ def __init__(
263
+ self,
264
+ *,
265
+ api_key: str | None = None,
266
+ base_url: str | None = None,
267
+ timeout_seconds: float = 30.0,
268
+ ) -> None:
269
+ credential = resolve_api_credential(api_key)
270
+ self._transport = HttpTransport(
271
+ base_url=normalize_backend_base(base_url or BACKEND_URL_BASE),
272
+ headers=credential.authorization_headers(),
273
+ timeout_seconds=timeout_seconds,
274
+ )
275
+ self.checkpoints = CheckpointsAPI(self._transport)
276
+ self.models = ModelsAPI(self._transport)
277
+ self.runs = RunsAPI(self._transport)
278
+
279
+ def close(self) -> None:
280
+ """Close the hosted optimizer HTTP transport."""
281
+ self._transport.close()
282
+
283
+
284
+ class AsyncOptimizersClient:
285
+ """Native asynchronous hosted optimizer namespace."""
286
+
287
+ def __init__(
288
+ self,
289
+ *,
290
+ api_key: str | None = None,
291
+ base_url: str | None = None,
292
+ timeout_seconds: float = 30.0,
293
+ ) -> None:
294
+ credential = resolve_api_credential(api_key)
295
+ self._transport = AsyncHttpTransport(
296
+ base_url=normalize_backend_base(base_url or BACKEND_URL_BASE),
297
+ headers=credential.authorization_headers(),
298
+ timeout_seconds=timeout_seconds,
299
+ )
300
+ self.checkpoints = AsyncCheckpointsAPI(self._transport)
301
+ self.models = AsyncModelsAPI(self._transport)
302
+ self.runs = AsyncRunsAPI(self._transport)
303
+
304
+ async def close(self) -> None:
305
+ """Close the asynchronous hosted optimizer HTTP transport."""
306
+ await self._transport.close()
307
+
308
+
309
+ __all__ = ["AsyncOptimizersClient", "OptimizersClient"]
@@ -0,0 +1,142 @@
1
+ """Typed public contracts for hosted optimizer model discovery and lineage."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+
10
+ class OptimizerContract(BaseModel):
11
+ """Forward-compatible base for optimizer API payloads."""
12
+
13
+ model_config = ConfigDict(extra="allow")
14
+
15
+
16
+ class SavedLoraStorage(OptimizerContract):
17
+ backend: str
18
+ bucket: str
19
+ key: str
20
+ version: str | None = None
21
+ etag: str | None = None
22
+ sha256: str | None = None
23
+ size_bytes: int | None = None
24
+ content_type: str
25
+
26
+
27
+ class SavedLoraLineage(OptimizerContract):
28
+ optimizer_algorithm: str | None = None
29
+ run_id: str | None = None
30
+ attempt_id: str | None = None
31
+ source_checkpoint_id: str | None = None
32
+ provider_checkpoint_reference: str | None = None
33
+
34
+
35
+ class SavedLoraCheckpoint(OptimizerContract):
36
+ schema_version: str = "saved_lora_checkpoint.v1"
37
+ checkpoint_id: str
38
+ org_id: str
39
+ owner_user_id: str | None = None
40
+ visibility: str
41
+ name: str
42
+ description: str = ""
43
+ provider: str
44
+ checkpoint_kind: str
45
+ provider_checkpoint_reference: str | None = None
46
+ optimizer_algorithm: str | None = None
47
+ run_id: str | None = None
48
+ attempt_id: str | None = None
49
+ source_checkpoint_id: str | None = None
50
+ base_model: str
51
+ lora_rank: int | None = None
52
+ step: int | None = None
53
+ status: str
54
+ storage: SavedLoraStorage
55
+ lineage: SavedLoraLineage = Field(default_factory=SavedLoraLineage)
56
+ tags: list[str] = Field(default_factory=list)
57
+ metadata: dict[str, Any] = Field(default_factory=dict)
58
+ created_at: str | None = None
59
+ updated_at: str | None = None
60
+ archived_at: str | None = None
61
+
62
+
63
+ class SavedLoraCheckpointPage(OptimizerContract):
64
+ items: list[SavedLoraCheckpoint]
65
+ total: int
66
+ limit: int
67
+ offset: int
68
+
69
+
70
+ class OptimizerRunIdentity(OptimizerContract):
71
+ run_id: str
72
+ attempt_id: str | None = None
73
+ optimizer_algorithm: str
74
+ status: str
75
+
76
+
77
+ class OptimizerRunArtifact(OptimizerContract):
78
+ artifact_id: str
79
+ run_id: str
80
+ artifact_name: str
81
+ content_type: str | None = None
82
+ size_bytes: int
83
+ sha256: str | None = None
84
+ storage_backend: str
85
+ uri: str
86
+ download_path: str
87
+ metadata: dict[str, Any] = Field(default_factory=dict)
88
+ created_at: str | None = None
89
+ updated_at: str | None = None
90
+
91
+
92
+ class OptimizerRunOutputs(OptimizerContract):
93
+ """All automatically persisted outputs for one optimizer run."""
94
+
95
+ schema_version: str = "optimizer.run_outputs.v1"
96
+ run: OptimizerRunIdentity
97
+ result: dict[str, Any] | None = None
98
+ artifacts: list[OptimizerRunArtifact]
99
+ model_checkpoints: list[SavedLoraCheckpoint]
100
+ counts: dict[str, int]
101
+
102
+
103
+ class SavedLoraRunPage(OptimizerContract):
104
+ schema_version: str = "saved_lora_checkpoint.run_page.v1"
105
+ run: OptimizerRunIdentity
106
+ items: list[SavedLoraCheckpoint]
107
+ counts: dict[str, int]
108
+ total: int
109
+ limit: int
110
+ offset: int
111
+
112
+
113
+ class HostedTrainingModel(OptimizerContract):
114
+ model_id: str
115
+ label: str
116
+ provider: str
117
+ provider_revision: str
118
+ architecture: str
119
+ max_context_length: int
120
+ rank: dict[str, int]
121
+ algorithms: dict[str, dict[str, Any]]
122
+
123
+
124
+ class HostedTrainingModelCatalog(OptimizerContract):
125
+ catalog_revision: str
126
+ live_preflight_required: bool
127
+ models: list[HostedTrainingModel]
128
+ total: int
129
+
130
+
131
+ __all__ = [
132
+ "HostedTrainingModel",
133
+ "HostedTrainingModelCatalog",
134
+ "OptimizerRunIdentity",
135
+ "OptimizerRunArtifact",
136
+ "OptimizerRunOutputs",
137
+ "SavedLoraCheckpoint",
138
+ "SavedLoraCheckpointPage",
139
+ "SavedLoraLineage",
140
+ "SavedLoraRunPage",
141
+ "SavedLoraStorage",
142
+ ]