synth-ai 0.22.2.dev688__tar.gz → 0.22.2.dev690__tar.gz

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