imbi-api 2.43.1__tar.gz → 2.45.0__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 (427) hide show
  1. {imbi_api-2.43.1 → imbi_api-2.45.0}/PKG-INFO +3 -2
  2. {imbi_api-2.43.1 → imbi_api-2.45.0}/pyproject.toml +3 -2
  3. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tools.py +14 -72
  4. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/internal_services.py +48 -4
  5. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/seed.py +24 -0
  6. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/component_facts.py +11 -8
  7. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_platform.py +9 -2
  8. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agents.py +53 -42
  9. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/ai_providers.py +268 -20
  10. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/dashboard.py +3 -5
  11. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/harness.py +155 -154
  12. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/mcp_servers.py +13 -270
  13. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/organizations.py +7 -0
  14. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_deployments.py +97 -9
  15. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/projects.py +143 -179
  16. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/pull_requests.py +183 -15
  17. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/releases.py +193 -36
  18. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/scoring.py +14 -12
  19. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/secret_broker.py +240 -7
  20. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/egress.py +94 -6
  21. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/platform.py +26 -2
  22. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/schemata.toml +9 -4
  23. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/store.py +25 -11
  24. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/tokens.py +52 -0
  25. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/lifespans.py +32 -7
  26. imbi_api-2.45.0/src/imbi/api/llm/tokens.py +109 -0
  27. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/assignments.py +72 -0
  28. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/resolution.py +2 -7
  29. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/release_promote/service.py +70 -21
  30. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/__init__.py +12 -2
  31. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/audit.py +11 -4
  32. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/broker.py +55 -6
  33. imbi_api-2.45.0/src/imbi/api/secret_broker/identity.py +288 -0
  34. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/providers.py +71 -31
  35. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/schemata.toml +16 -0
  36. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/store.py +61 -0
  37. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/settings.py +63 -1
  38. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_internal_services.py +30 -3
  39. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_seed.py +2 -0
  40. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_platform.py +7 -0
  41. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_tasks.py +19 -0
  42. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agents.py +11 -7
  43. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_ai_providers.py +275 -2
  44. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_components.py +4 -2
  45. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_dashboard.py +7 -3
  46. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_harness.py +0 -223
  47. imbi_api-2.45.0/tests/endpoints/test_harness_egress.py +951 -0
  48. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_harness_secrets.py +0 -246
  49. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_mcp_servers.py +23 -0
  50. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_deployments.py +172 -0
  51. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_projects.py +98 -195
  52. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_projects_helpers.py +5 -2
  53. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_pull_requests.py +113 -0
  54. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_releases.py +328 -4
  55. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_secret_broker.py +228 -2
  56. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/secret_support.py +26 -10
  57. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_agent_platform.py +44 -0
  58. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_agent_tools.py +36 -153
  59. imbi_api-2.45.0/tests/test_ai_provider_tokens.py +116 -0
  60. imbi_api-2.45.0/tests/test_clickhouse_project_ids.py +40 -0
  61. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_lifespans.py +25 -1
  62. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugins.py +40 -0
  63. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugins_assignments.py +161 -0
  64. imbi_api-2.45.0/tests/test_pull_request_resync_clickhouse.py +237 -0
  65. imbi_api-2.45.0/tests/test_pull_request_reviews_clickhouse.py +108 -0
  66. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_pull_requests_pending_deploy.py +6 -1
  67. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_release_promote_service.py +69 -0
  68. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_secret_broker.py +62 -0
  69. imbi_api-2.45.0/tests/test_secret_identity.py +259 -0
  70. imbi_api-2.43.1/tests/endpoints/test_harness_egress.py +0 -470
  71. {imbi_api-2.43.1 → imbi_api-2.45.0}/.gitignore +0 -0
  72. {imbi_api-2.43.1 → imbi_api-2.45.0}/README.md +0 -0
  73. {imbi_api-2.43.1 → imbi_api-2.45.0}/moon.yml +0 -0
  74. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/README.md +0 -0
  75. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/__init__.py +0 -0
  76. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/__init__.py +0 -0
  77. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/log.py +0 -0
  78. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/schemata.toml +0 -0
  79. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/store.py +0 -0
  80. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/sweeper.py +0 -0
  81. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/app.py +0 -0
  82. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/__init__.py +0 -0
  83. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/agent_api.py +0 -0
  84. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/agent_api_routes.py +0 -0
  85. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/authorization_codes.py +0 -0
  86. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/autonomous.py +0 -0
  87. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/local_auth.py +0 -0
  88. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/login_providers.py +0 -0
  89. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/membership.py +0 -0
  90. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/models.py +0 -0
  91. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/oauth_clients.py +0 -0
  92. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/organizations.py +0 -0
  93. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/password.py +0 -0
  94. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/permissions.py +0 -0
  95. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/principals.py +0 -0
  96. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/sessions.py +0 -0
  97. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/tokens.py +0 -0
  98. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/totp.py +0 -0
  99. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/backfill_embeddings.py +0 -0
  100. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/blueprint_attributes.py +0 -0
  101. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/blueprint_compliance.py +0 -0
  102. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_pushed_at_repair.py +0 -0
  103. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_sync/__init__.py +0 -0
  104. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_sync/queue.py +0 -0
  105. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_sync/service.py +0 -0
  106. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_status_repair.py +0 -0
  107. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sweeper.py +0 -0
  108. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sync/__init__.py +0 -0
  109. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sync/queue.py +0 -0
  110. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sync/service.py +0 -0
  111. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/documents/__init__.py +0 -0
  112. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/documents/read_sweeper.py +0 -0
  113. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/domain/__init__.py +0 -0
  114. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/domain/models.py +0 -0
  115. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/domain/scoring.py +0 -0
  116. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/drift.py +0 -0
  117. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/__init__.py +0 -0
  118. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/client.py +0 -0
  119. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/dependencies.py +0 -0
  120. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/models.py +0 -0
  121. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/base.html +0 -0
  122. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/base.txt +0 -0
  123. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/password_reset.html +0 -0
  124. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/password_reset.txt +0 -0
  125. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/welcome.html +0 -0
  126. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/welcome.txt +0 -0
  127. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates.py +0 -0
  128. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/__init__.py +0 -0
  129. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_credentials.py +0 -0
  130. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_events.py +0 -0
  131. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_history.py +0 -0
  132. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_reads.py +0 -0
  133. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_scope.py +0 -0
  134. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_helpers.py +0 -0
  135. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_json_fields.py +0 -0
  136. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_pagination.py +0 -0
  137. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_request_urls.py +0 -0
  138. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_search_index.py +0 -0
  139. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/admin.py +0 -0
  140. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/admin_plugins.py +0 -0
  141. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_task_harness.py +0 -0
  142. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_tasks.py +0 -0
  143. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_usage.py +0 -0
  144. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/ai_models.py +0 -0
  145. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/api_keys.py +0 -0
  146. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/auth.py +0 -0
  147. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/auth_providers.py +0 -0
  148. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/blueprints.py +0 -0
  149. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/client_credentials.py +0 -0
  150. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/comments.py +0 -0
  151. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/components.py +0 -0
  152. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_analytics.py +0 -0
  153. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_likes.py +0 -0
  154. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_presence.py +0 -0
  155. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_templates.py +0 -0
  156. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_versions.py +0 -0
  157. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/documents.py +0 -0
  158. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/environments.py +0 -0
  159. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/events.py +0 -0
  160. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/graph_query.py +0 -0
  161. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/iggy_connectors.py +0 -0
  162. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/integrations.py +0 -0
  163. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/link_definitions.py +0 -0
  164. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/local_auth.py +0 -0
  165. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/maintenance.py +0 -0
  166. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/mfa.py +0 -0
  167. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/oauth_metadata.py +0 -0
  168. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/operations_log.py +0 -0
  169. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/plugin_edges.py +0 -0
  170. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/plugin_entities.py +0 -0
  171. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/plugins.py +0 -0
  172. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_analysis.py +0 -0
  173. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_commit_sync.py +0 -0
  174. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_configuration.py +0 -0
  175. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_incidents.py +0 -0
  176. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_integrations.py +0 -0
  177. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_lifecycle.py +0 -0
  178. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_logs.py +0 -0
  179. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_plugins.py +0 -0
  180. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_pr_sync.py +0 -0
  181. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_types.py +0 -0
  182. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/prompts.py +0 -0
  183. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/roles.py +0 -0
  184. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/sa_api_keys.py +0 -0
  185. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/scoring_policies.py +0 -0
  186. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/search.py +0 -0
  187. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/service_accounts.py +0 -0
  188. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/status.py +0 -0
  189. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/tags.py +0 -0
  190. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/teams.py +0 -0
  191. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/uploads.py +0 -0
  192. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/user_activity.py +0 -0
  193. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/users.py +0 -0
  194. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/webhooks.py +0 -0
  195. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/workflow_runs.py +0 -0
  196. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/workflows.py +0 -0
  197. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/entrypoint.py +0 -0
  198. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/graph_ids.py +0 -0
  199. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/graph_sql.py +0 -0
  200. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/__init__.py +0 -0
  201. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/auth.py +0 -0
  202. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/marketplaces.py +0 -0
  203. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/metrics.py +0 -0
  204. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/sweeper.py +0 -0
  205. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/__init__.py +0 -0
  206. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/attribution.py +0 -0
  207. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/endpoints.py +0 -0
  208. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/errors.py +0 -0
  209. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/flows.py +0 -0
  210. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/host_integration.py +0 -0
  211. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/models.py +0 -0
  212. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/repository.py +0 -0
  213. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/resolution.py +0 -0
  214. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/state.py +0 -0
  215. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/sweeper.py +0 -0
  216. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/iggy_metrics.py +0 -0
  217. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/llm/__init__.py +0 -0
  218. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/llm/dependencies.py +0 -0
  219. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/__init__.py +0 -0
  220. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/log.py +0 -0
  221. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/operations.py +0 -0
  222. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/registry.py +0 -0
  223. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/state.py +0 -0
  224. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/worker.py +0 -0
  225. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/mcp_test.py +0 -0
  226. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/middleware/__init__.py +0 -0
  227. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/middleware/rate_limit.py +0 -0
  228. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/models.py +0 -0
  229. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/openapi.py +0 -0
  230. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/orphan_releases.py +0 -0
  231. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/__init__.py +0 -0
  232. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/assignment_writer.py +0 -0
  233. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/credentials.py +0 -0
  234. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/installer.py +0 -0
  235. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/lifecycle.py +0 -0
  236. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/lifecycle_dispatch.py +0 -0
  237. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/reload.py +0 -0
  238. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/schemas.py +0 -0
  239. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/pr_sync/__init__.py +0 -0
  240. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/pr_sync/queue.py +0 -0
  241. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/pr_sync/service.py +0 -0
  242. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/prompts/__init__.py +0 -0
  243. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/prompts/release_notes_system.md +0 -0
  244. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/prompts/seed.py +0 -0
  245. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/py.typed +0 -0
  246. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/relationships.py +0 -0
  247. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/release_promote/__init__.py +0 -0
  248. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/release_promote/queue.py +0 -0
  249. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/sbom.py +0 -0
  250. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/scoring/__init__.py +0 -0
  251. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/scoring/queue.py +0 -0
  252. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/__init__.py +0 -0
  253. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/client.py +0 -0
  254. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/dependencies.py +0 -0
  255. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/thumbnails.py +0 -0
  256. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/validation.py +0 -0
  257. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/user_document_orgs.py +0 -0
  258. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/__init__.py +0 -0
  259. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/runs.py +0 -0
  260. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/runtime_schemata.toml +0 -0
  261. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/schemata.toml +0 -0
  262. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/store.py +0 -0
  263. {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/sweeper.py +0 -0
  264. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/__init__.py +0 -0
  265. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/__init__.py +0 -0
  266. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_authentication.py +0 -0
  267. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_authorization.py +0 -0
  268. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_encryption.py +0 -0
  269. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_login_providers.py +0 -0
  270. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_membership.py +0 -0
  271. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_oauth_server.py +0 -0
  272. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_organizations.py +0 -0
  273. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_permissions.py +0 -0
  274. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_sessions.py +0 -0
  275. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_totp.py +0 -0
  276. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/__init__.py +0 -0
  277. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/test_client.py +0 -0
  278. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/test_init.py +0 -0
  279. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/test_privacy.py +0 -0
  280. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/__init__.py +0 -0
  281. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_audit_clickhouse.py +0 -0
  282. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_client.py +0 -0
  283. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_init.py +0 -0
  284. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_integration.py +0 -0
  285. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_models.py +0 -0
  286. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_templates.py +0 -0
  287. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/__init__.py +0 -0
  288. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_admin.py +0 -0
  289. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_admin_plugins.py +0 -0
  290. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_api.py +0 -0
  291. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_actions.py +0 -0
  292. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_harness.py +0 -0
  293. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_log.py +0 -0
  294. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_relations.py +0 -0
  295. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_usage.py +0 -0
  296. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_ai_models.py +0 -0
  297. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_api_keys.py +0 -0
  298. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_auth.py +0 -0
  299. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_auth_providers.py +0 -0
  300. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_blueprints.py +0 -0
  301. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_client_credentials.py +0 -0
  302. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_comments.py +0 -0
  303. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_credentials.py +0 -0
  304. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_cross_org_reads.py +0 -0
  305. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_analytics.py +0 -0
  306. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_likes.py +0 -0
  307. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_presence.py +0 -0
  308. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_reads.py +0 -0
  309. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_reads_sql.py +0 -0
  310. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_templates.py +0 -0
  311. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_versions.py +0 -0
  312. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_documents.py +0 -0
  313. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_environments.py +0 -0
  314. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_events.py +0 -0
  315. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_github_app_repository.py +0 -0
  316. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_graph_query.py +0 -0
  317. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_iggy_connectors.py +0 -0
  318. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_init.py +0 -0
  319. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_integrations.py +0 -0
  320. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_json_fields.py +0 -0
  321. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_link_definitions.py +0 -0
  322. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_local_auth.py +0 -0
  323. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_maintenance.py +0 -0
  324. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_mfa.py +0 -0
  325. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_operations_log.py +0 -0
  326. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_organizations.py +0 -0
  327. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_pagination.py +0 -0
  328. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_plugin_label_validation.py +0 -0
  329. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_plugins.py +0 -0
  330. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_analysis.py +0 -0
  331. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_commit_sync.py +0 -0
  332. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_configuration.py +0 -0
  333. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_deployments_autonomous.py +0 -0
  334. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_incidents.py +0 -0
  335. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_integrations.py +0 -0
  336. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_lifecycle.py +0 -0
  337. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_logs.py +0 -0
  338. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_plugins.py +0 -0
  339. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_response_surfacing.py +0 -0
  340. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_types.py +0 -0
  341. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_prompt_decisions.py +0 -0
  342. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_prompts.py +0 -0
  343. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_request_urls.py +0 -0
  344. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_roles.py +0 -0
  345. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_sa_api_keys.py +0 -0
  346. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_scoring.py +0 -0
  347. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_scoring_policies.py +0 -0
  348. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_search.py +0 -0
  349. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_search_index.py +0 -0
  350. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_service_accounts.py +0 -0
  351. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_service_writeback.py +0 -0
  352. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_status.py +0 -0
  353. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_tags.py +0 -0
  354. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_teams.py +0 -0
  355. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_uploads.py +0 -0
  356. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_user_activity.py +0 -0
  357. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_users.py +0 -0
  358. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_webhooks.py +0 -0
  359. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflow_run_history.py +0 -0
  360. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflow_runs.py +0 -0
  361. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflow_triggers.py +0 -0
  362. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflows.py +0 -0
  363. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/marketplaces/claude-code.json +0 -0
  364. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/sbom/npm-realistic.json +0 -0
  365. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/sbom/pypi-realistic.json +0 -0
  366. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/sbom/tiny.json +0 -0
  367. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/__init__.py +0 -0
  368. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_endpoints.py +0 -0
  369. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_errors.py +0 -0
  370. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_flows.py +0 -0
  371. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_host_integration.py +0 -0
  372. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_repository.py +0 -0
  373. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_resolution.py +0 -0
  374. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_state.py +0 -0
  375. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_sweeper.py +0 -0
  376. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/middleware/test_rate_limit.py +0 -0
  377. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/__init__.py +0 -0
  378. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_client.py +0 -0
  379. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_init.py +0 -0
  380. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_thumbnails.py +0 -0
  381. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_validation.py +0 -0
  382. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/support.py +0 -0
  383. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_agent_task_events_e2e.py +0 -0
  384. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_app.py +0 -0
  385. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_assignment_writer.py +0 -0
  386. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_auth_settings.py +0 -0
  387. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_backfill_embeddings.py +0 -0
  388. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_blueprint_attributes.py +0 -0
  389. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_blueprint_compliance.py +0 -0
  390. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_blueprints.py +0 -0
  391. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_commit_pushed_at_repair.py +0 -0
  392. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_commit_sync_queue.py +0 -0
  393. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_commit_sync_service.py +0 -0
  394. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_component_facts.py +0 -0
  395. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_status_repair.py +0 -0
  396. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_sweeper.py +0 -0
  397. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_sync_queue.py +0 -0
  398. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_sync_service.py +0 -0
  399. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_drift.py +0 -0
  400. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_entrypoint.py +0 -0
  401. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_graph_ids.py +0 -0
  402. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_graph_sql.py +0 -0
  403. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_identity_attribution.py +0 -0
  404. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_iggy_metrics.py +0 -0
  405. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_init.py +0 -0
  406. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_installer.py +0 -0
  407. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_lifecycle_dispatch.py +0 -0
  408. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_log.py +0 -0
  409. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_operations.py +0 -0
  410. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_state.py +0 -0
  411. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_worker.py +0 -0
  412. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_models.py +0 -0
  413. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_openapi.py +0 -0
  414. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_orphan_releases.py +0 -0
  415. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugin_schemas.py +0 -0
  416. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugins_credentials.py +0 -0
  417. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_pr_sync_queue.py +0 -0
  418. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_pr_sync_service.py +0 -0
  419. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_projects_drift_ranges.py +0 -0
  420. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_prompt_seed.py +0 -0
  421. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_sbom.py +0 -0
  422. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_scoring_queue.py +0 -0
  423. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_scoring_triggers.py +0 -0
  424. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_secret_github_app.py +0 -0
  425. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_secret_providers.py +0 -0
  426. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_settings.py +0 -0
  427. {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_workflow_reconcile.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: imbi-api
3
- Version: 2.43.1
3
+ Version: 2.45.0
4
4
  Summary: Imbi is a DevOps Service Management Platform designed to provide an efficient way to manage a large environment that contains many services and applications.
5
5
  Author-email: Alex Campbell <alexc@aweber.com>, Dave Shawley <daves@aweber.com>, "Gavin M. Roy" <gavinr@aweber.com>
6
6
  License-Expression: BSD-3-Clause
@@ -19,7 +19,8 @@ Requires-Dist: cyclonedx-python-lib<12,>=11.7
19
19
  Requires-Dist: fastapi
20
20
  Requires-Dist: filetype
21
21
  Requires-Dist: httpx<1,>=0.28.1
22
- Requires-Dist: imbi-common[databases,llm,mcp,sentry,server]==2.43.1
22
+ Requires-Dist: idna>=3.18
23
+ Requires-Dist: imbi-common[databases,llm,mcp,sentry,server]==2.45.0
23
24
  Requires-Dist: jinja2
24
25
  Requires-Dist: jsonpatch>=1.33
25
26
  Requires-Dist: limits<6,>=5
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "imbi-api"
3
- version = "2.43.1"
3
+ version = "2.45.0"
4
4
  description = "Imbi is a DevOps Service Management Platform designed to provide an efficient way to manage a large environment that contains many services and applications."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -28,7 +28,8 @@ dependencies = [
28
28
  "fastapi",
29
29
  "filetype",
30
30
  "httpx>=0.28.1,<1",
31
- "imbi-common[databases,llm,mcp,sentry,server]==2.43.1",
31
+ "idna>=3.18",
32
+ "imbi-common[databases,llm,mcp,sentry,server]==2.45.0",
32
33
  "jinja2",
33
34
  "jsonpatch>=1.33",
34
35
  "limits>=5,<6",
@@ -1,19 +1,15 @@
1
1
  """The catalog of tools that an agent can use.
2
2
 
3
- The catalog has one group for each tool server:
3
+ The catalog has one group, ``imbi``: the tools that imbi-mcp and
4
+ imbi-assistant make from the OpenAPI document of this API. This module
5
+ makes them in the same way, in this process, so the names are the
6
+ same. The MCP servers in Admin > Assistant are for the assistant only.
7
+ An agent gets other MCP servers from the plugins of its marketplaces.
4
8
 
5
- * ``imbi``: the tools that imbi-mcp and imbi-assistant make from the
6
- OpenAPI document of this API. This module makes them in the same
7
- way, in this process, so the names are the same.
8
- * One group for each enabled :class:`~imbi.common.models.MCPServer`.
9
- The tools are listed live, with the client code of the connection
10
- test. ``ignored_tools`` is applied.
11
-
12
- A server that fails gives its group with an :data:`ErrorCode` in
13
- ``error`` and no tools. The other groups are not affected. The error
14
- text can show internal hosts, URLs, or parts of credentials, so it
15
- goes only to the log, never to the response or to the cache. The
16
- catalog is kept in Valkey for :data:`CACHE_TTL_SECONDS`.
9
+ When the tools cannot be made, the group has an :data:`ErrorCode` in
10
+ ``error`` and no tools. The error text goes only to the log, never to
11
+ the response or to the cache. The catalog is kept in Valkey for
12
+ :data:`CACHE_TTL_SECONDS`.
17
13
 
18
14
  A tool key is ``<server slug>.<tool name>``. An agent stores its tool
19
15
  configuration by this key.
@@ -31,8 +27,6 @@ import pydantic
31
27
  from mcp import types as mcp_types
32
28
  from valkey import asyncio as valkey
33
29
 
34
- from imbi.api import mcp_test
35
- from imbi.common import graph, models
36
30
  from imbi.common import mcp as common_mcp
37
31
 
38
32
  LOGGER = logging.getLogger(__name__)
@@ -40,10 +34,6 @@ LOGGER = logging.getLogger(__name__)
40
34
  CACHE_KEY = 'imbi:agents:tool-catalog'
41
35
  CACHE_TTL_SECONDS = 300
42
36
 
43
- #: The limit for one MCP server, in seconds. A server with a smaller
44
- #: ``timeout`` uses its own value.
45
- SERVER_TIMEOUT_SECONDS = 10.0
46
-
47
37
  #: The server slug of the Imbi tools.
48
38
  IMBI_SERVER_SLUG = 'imbi'
49
39
 
@@ -51,7 +41,7 @@ IMBI_SERVER_SLUG = 'imbi'
51
41
  DESCRIPTION_LENGTH = 300
52
42
 
53
43
  Capability = typing.Literal['read', 'write', 'destructive', 'unknown']
54
- Transport = typing.Literal['internal', 'mcp/http']
44
+ Transport = typing.Literal['internal']
55
45
 
56
46
  #: Why the tools of a server could not be listed. ``auth_failed`` is
57
47
  #: an HTTP 401 or 403 response. ``unreachable`` is each other failure.
@@ -151,45 +141,6 @@ def _error_code(err: BaseException) -> ErrorCode:
151
141
  return 'unreachable'
152
142
 
153
143
 
154
- async def _mcp_group(server: models.MCPServer) -> AgentToolGroup:
155
- """List the tools of one MCP server. Never raises."""
156
- group = AgentToolGroup(
157
- server=AgentToolServer(
158
- slug=server.slug, name=server.name, transport='mcp/http'
159
- )
160
- )
161
- timeout_s = min(float(server.timeout), SERVER_TIMEOUT_SECONDS)
162
- try:
163
- async with asyncio.timeout(timeout_s):
164
- tools = await mcp_test.list_tools(server, timeout_s)
165
- except asyncio.CancelledError:
166
- raise
167
- except TimeoutError:
168
- LOGGER.warning(
169
- 'Cannot list the tools of %r: timed out after %gs',
170
- server.slug,
171
- timeout_s,
172
- )
173
- group.error = 'timeout'
174
- return group
175
- except Exception as err: # noqa: BLE001 - one server must not fail all
176
- LOGGER.warning(
177
- 'Cannot list the tools of %r: %s', server.slug, err, exc_info=err
178
- )
179
- group.error = _error_code(err)
180
- return group
181
- ignored = set(server.ignored_tools)
182
- group.tools = sorted(
183
- (
184
- _tool(server.slug, t.name, t.description, t.annotations)
185
- for t in tools
186
- if t.name not in ignored
187
- ),
188
- key=lambda t: t.name,
189
- )
190
- return group
191
-
192
-
193
144
  def _imbi_server(
194
145
  spec: dict[str, typing.Any], client: httpx.AsyncClient
195
146
  ) -> fastmcp.FastMCP[typing.Any]:
@@ -234,24 +185,15 @@ async def _imbi_group(spec: dict[str, typing.Any]) -> AgentToolGroup:
234
185
  return group
235
186
 
236
187
 
237
- async def build_catalog(
238
- db: graph.Pool, spec: dict[str, typing.Any]
239
- ) -> AgentToolCatalog:
240
- """List every group now, at the same time."""
241
- servers = await db.match(
242
- models.MCPServer, {'enabled': True}, order_by='name'
243
- )
244
- groups = await asyncio.gather(
245
- _imbi_group(spec), *(_mcp_group(server) for server in servers)
246
- )
188
+ async def build_catalog(spec: dict[str, typing.Any]) -> AgentToolCatalog:
189
+ """List the catalog now."""
247
190
  return AgentToolCatalog(
248
- groups=list(groups),
191
+ groups=[await _imbi_group(spec)],
249
192
  generated_at=datetime.datetime.now(datetime.UTC),
250
193
  )
251
194
 
252
195
 
253
196
  async def get_catalog(
254
- db: graph.Pool,
255
197
  client: valkey.Valkey | None,
256
198
  spec: collections.abc.Callable[[], dict[str, typing.Any]],
257
199
  *,
@@ -275,7 +217,7 @@ async def get_catalog(
275
217
  return AgentToolCatalog.model_validate_json(cached)
276
218
  except pydantic.ValidationError:
277
219
  LOGGER.debug('discarding malformed tool catalog cache entry')
278
- catalog = await build_catalog(db, spec())
220
+ catalog = await build_catalog(spec())
279
221
  if client is not None:
280
222
  try:
281
223
  await client.set(
@@ -9,9 +9,9 @@ patch projects and record releases. Neither is created by hand any more:
9
9
  existing install up to date. ``imbi-workflows`` calls imbi-api as its
10
10
  own account for the deploy and rollback steps of a workflow (ADR 0021).
11
11
 
12
- imbi-assistant, imbi-mcp, and imbi-slackbot deliberately have no entry
13
- here. Each forwards the *caller's* token to imbi-api rather than acting
14
- as itself, so an account for them would carry privileges nothing uses.
12
+ imbi-assistant and imbi-slackbot forward the *caller's* token for
13
+ their tool calls. Their own accounts only get the token of their AI
14
+ Provider (WIF plan 4.6, ``ai_provider:token``). imbi-mcp has no entry.
15
15
 
16
16
  Credentials come from the environment when it supplies them, so a
17
17
  deployment whose secret already lives in a Helm values file or an
@@ -56,6 +56,10 @@ class InternalService(typing.NamedTuple):
56
56
  #: ``secret_var``.
57
57
  client_id_var: str | None
58
58
  secret_var: str
59
+ #: Skip this service, with a warning, when its role is not seeded.
60
+ #: Set for services added after release: an upgrade that has not
61
+ #: run ``setup-permissions`` yet must not stop the existing ones.
62
+ optional: bool = False
59
63
 
60
64
 
61
65
  INTERNAL_SERVICES: tuple[InternalService, ...] = (
@@ -91,6 +95,26 @@ INTERNAL_SERVICES: tuple[InternalService, ...] = (
91
95
  client_id_var='IMBI_WORKFLOWS_SA_CLIENT_ID',
92
96
  secret_var='IMBI_WORKFLOWS_SA_CLIENT_SECRET',
93
97
  ),
98
+ InternalService(
99
+ slug='imbi-assistant',
100
+ display_name='Imbi Assistant',
101
+ description='Gets the token of its AI provider (WIF plan 4.6)',
102
+ role_slug='imbi-assistant',
103
+ credential='api_key',
104
+ client_id_var=None,
105
+ secret_var='IMBI_ASSISTANT_API_TOKEN',
106
+ optional=True,
107
+ ),
108
+ InternalService(
109
+ slug='imbi-slackbot',
110
+ display_name='Imbi Slackbot',
111
+ description='Gets the token of its AI provider (WIF plan 4.6)',
112
+ role_slug='imbi-slackbot',
113
+ credential='api_key',
114
+ client_id_var=None,
115
+ secret_var='IMBI_SLACKBOT_API_TOKEN',
116
+ optional=True,
117
+ ),
94
118
  )
95
119
 
96
120
 
@@ -136,7 +160,8 @@ async def seed_internal_services(
136
160
 
137
161
  Returns:
138
162
  One :class:`SeededService` per :data:`INTERNAL_SERVICES`, in
139
- declaration order.
163
+ declaration order, less any optional service whose role is
164
+ missing.
140
165
 
141
166
  Raises:
142
167
  SeedError: A role or the organization is missing, or a supplied
@@ -146,6 +171,14 @@ async def seed_internal_services(
146
171
  env = os.environ if environ is None else environ
147
172
  results: list[SeededService] = []
148
173
  for service in INTERNAL_SERVICES:
174
+ if service.optional and not await _role_exists(db, service):
175
+ LOGGER.warning(
176
+ 'Skipping service account %s: role %s not found. '
177
+ 'Run imbi-api setup-permissions to seed it.',
178
+ service.slug,
179
+ service.role_slug,
180
+ )
181
+ continue
149
182
  created = await _ensure_account(db, service, org_slug)
150
183
  if service.credential == 'client_credential':
151
184
  outcome, emit = await _ensure_client_credential(db, service, env)
@@ -161,6 +194,17 @@ async def seed_internal_services(
161
194
  return results
162
195
 
163
196
 
197
+ async def _role_exists(db: graph.Graph, service: InternalService) -> bool:
198
+ """Report whether the role of *service* is seeded."""
199
+ return bool(
200
+ await db.execute(
201
+ 'MATCH (r:Role {{slug: {role_slug}}}) RETURN r.slug AS slug',
202
+ {'role_slug': service.role_slug},
203
+ ['slug'],
204
+ )
205
+ )
206
+
207
+
164
208
  async def _ensure_account(
165
209
  db: graph.Graph,
166
210
  service: InternalService,
@@ -148,6 +148,12 @@ STANDARD_PERMISSIONS: list[tuple[str, str, str, str]] = [
148
148
  'credentials',
149
149
  'Set or remove AI provider credentials',
150
150
  ),
151
+ (
152
+ 'ai_provider:token',
153
+ 'ai_provider',
154
+ 'token',
155
+ 'Get the AI provider token of the calling service',
156
+ ),
151
157
  # Prompt CMS. ``promote`` is separate from ``update``: moving a
152
158
  # label changes what every consumer of that label runs, without
153
159
  # any change to a prompt body.
@@ -1046,6 +1052,24 @@ DEFAULT_ROLES: list[tuple[str, str, str, int, list[str], bool]] = [
1046
1052
  ],
1047
1053
  False,
1048
1054
  ),
1055
+ (
1056
+ 'imbi-assistant',
1057
+ 'Imbi Assistant',
1058
+ 'Service role for imbi-assistant: get the token of its AI '
1059
+ 'provider (WIF plan 4.6)',
1060
+ 900,
1061
+ ['ai_provider:token'],
1062
+ False,
1063
+ ),
1064
+ (
1065
+ 'imbi-slackbot',
1066
+ 'Imbi Slackbot',
1067
+ 'Service role for imbi-slackbot: get the token of its AI '
1068
+ 'provider (WIF plan 4.6)',
1069
+ 900,
1070
+ ['ai_provider:token'],
1071
+ False,
1072
+ ),
1049
1073
  ]
1050
1074
 
1051
1075
  # Invariant: exactly one seeded role is the auto-assignment target so
@@ -78,7 +78,7 @@ _BATCHES_BY_PROJECT = (
78
78
  'SELECT release_id,'
79
79
  " argMax(batch_id, (source = 'ingest', recorded_at)) AS batch_id"
80
80
  ' FROM imbi.release_component_batches'
81
- ' WHERE project_id IN {project_ids:Array(String)}'
81
+ ' WHERE project_id IN (SELECT project_id FROM project_ids)'
82
82
  ' GROUP BY release_id'
83
83
  )
84
84
 
@@ -101,9 +101,9 @@ _JOIN = (
101
101
  def _by_project(select: str, where: str = '') -> str:
102
102
  """Compose a project-scoped read against the winning batches."""
103
103
  return (
104
- f'{select} FROM imbi.release_components AS c'
104
+ f'{select} FROM imbi.release_components AS c' # noqa: S608
105
105
  + _JOIN.format(batches=_BATCHES_BY_PROJECT)
106
- + ' WHERE c.project_id IN {project_ids:Array(String)}'
106
+ + ' WHERE c.project_id IN (SELECT project_id FROM project_ids)'
107
107
  + where
108
108
  )
109
109
 
@@ -148,13 +148,14 @@ async def component_ids_in_org(
148
148
  if not project_ids or component_ids == []:
149
149
  return set()
150
150
  where = ''
151
- params: dict[str, typing.Any] = {'project_ids': project_ids}
151
+ params: dict[str, typing.Any] = {}
152
152
  if component_ids is not None:
153
153
  where = ' AND c.component_id IN {component_ids:Array(String)}'
154
154
  params['component_ids'] = component_ids
155
155
  rows = await clickhouse.query(
156
156
  _by_project('SELECT DISTINCT c.component_id AS component_id', where),
157
157
  params,
158
+ project_ids=project_ids,
158
159
  )
159
160
  return {str(row['component_id']) for row in rows}
160
161
 
@@ -172,7 +173,8 @@ async def component_in_org(project_ids: list[str], component_id: str) -> bool:
172
173
  'SELECT 1 AS hit',
173
174
  ' AND c.component_id = {component_id:String} LIMIT 1',
174
175
  ),
175
- {'project_ids': project_ids, 'component_id': component_id},
176
+ {'component_id': component_id},
177
+ project_ids=project_ids,
176
178
  )
177
179
  return bool(rows)
178
180
 
@@ -200,10 +202,10 @@ async def component_release_in_org(
200
202
  ' LIMIT 1',
201
203
  ),
202
204
  {
203
- 'project_ids': project_ids,
204
205
  'component_id': component_id,
205
206
  'component_release_id': component_release_id,
206
207
  },
208
+ project_ids=project_ids,
207
209
  )
208
210
  return bool(rows)
209
211
 
@@ -227,7 +229,8 @@ async def search_counts(
227
229
  ' AND c.component_id IN {component_ids:Array(String)}'
228
230
  ' GROUP BY c.component_id',
229
231
  ),
230
- {'project_ids': project_ids, 'component_ids': component_ids},
232
+ {'component_ids': component_ids},
233
+ project_ids=project_ids,
231
234
  )
232
235
  return {
233
236
  str(row['component_id']): (
@@ -255,7 +258,7 @@ async def ecosystem_totals(project_ids: list[str]) -> dict[str, int]:
255
258
  ' uniqExact(c.component_id) AS total',
256
259
  " AND c.ecosystem != '' GROUP BY c.ecosystem",
257
260
  ),
258
- {'project_ids': project_ids},
261
+ project_ids=project_ids,
259
262
  )
260
263
  return {str(row['ecosystem']): int(row['total']) for row in rows}
261
264
 
@@ -127,10 +127,17 @@ async def put_agent_platform_config(
127
127
 
128
128
  Raises:
129
129
  409: A concurrent write took the version.
130
- 422: An allowed marketplace is not registered, or a default
131
- plugin is not in an allowed marketplace's catalog.
130
+ 422: An allowed marketplace is not registered, a default
131
+ plugin is not in an allowed marketplace's catalog, or the
132
+ model upstream URL is ``http://`` without
133
+ ``allow_insecure_http``.
132
134
 
133
135
  """
136
+ if data.model_upstream.insecure():
137
+ raise _unprocessable(
138
+ 'model_upstream.base_url must use https:// unless '
139
+ 'allow_insecure_http is true'
140
+ )
134
141
  found = {row['slug']: row for row in await store.marketplaces(org_id)}
135
142
  missing = sorted(set(data.allowed_marketplaces) - set(found))
136
143
  if missing:
@@ -468,7 +468,7 @@ def _props(raw: typing.Any) -> dict[str, typing.Any] | None:
468
468
 
469
469
 
470
470
  async def _service_account_params(
471
- db: graph.Graph, agent_id: str, name: str
471
+ execute: graph.CypherExecute, agent_id: str, name: str
472
472
  ) -> dict[str, typing.Any]:
473
473
  """Return the parameters of :data:`_CREATE_SERVICE_ACCOUNT`.
474
474
 
@@ -485,7 +485,7 @@ async def _service_account_params(
485
485
  if (
486
486
  not slug
487
487
  or slug.startswith('imbi-')
488
- or await db.execute(_SA_SLUG_TAKEN_QUERY, {'slug': slug}, ['id'])
488
+ or await execute(_SA_SLUG_TAKEN_QUERY, {'slug': slug}, ['id'])
489
489
  ):
490
490
  slug = slugify.slugify(f'{name} {agent_id}')
491
491
  if slug.startswith('imbi-'):
@@ -506,39 +506,51 @@ async def ensure_service_account(
506
506
 
507
507
  Make the service account when the agent has none. Agents made before
508
508
  service accounts existed get one here, so no backfill is necessary.
509
+
510
+ The read, the slug check, and the create run in one transaction
511
+ under an advisory lock on the agent id. Thus two concurrent calls
512
+ for one agent cannot both make an account: the second call waits,
513
+ then reads the account of the first.
509
514
  """
510
- records = await db.execute(
511
- _SERVICE_ACCOUNT_QUERY, {'id': agent_id}, ['id']
512
- )
513
- attempts = 3
514
- while not records and attempts:
515
- attempts -= 1
516
- params = await _service_account_params(db, agent_id, name)
517
- # Read again after the slug check. When a concurrent request
518
- # made the account of this agent first, its slug looks taken,
519
- # and this read finds that account. Thus the agent does not
520
- # get a second account.
521
- records = await db.execute(
515
+
516
+ async def ensure(
517
+ execute: graph.CypherExecute,
518
+ ) -> list[dict[str, typing.Any]]:
519
+ """Read or make the service account under the lock.
520
+
521
+ Read again first: a concurrent call can have made the account
522
+ after the fast path read.
523
+ """
524
+ records = await execute(
522
525
  _SERVICE_ACCOUNT_QUERY, {'id': agent_id}, ['id']
523
526
  )
524
527
  if records:
525
- break
526
- try:
527
- # Empty when the agent does not exist.
528
- records = await db.execute(
529
- _ENSURE_SERVICE_ACCOUNT_QUERY,
530
- {'id': agent_id, **params},
531
- ['id'],
532
- )
533
- break
534
- except psycopg.errors.UniqueViolation as exc:
535
- if not attempts:
536
- raise fastapi.HTTPException(
537
- status_code=409,
538
- detail=f'Service account slug for {name!r} is in use',
539
- ) from exc
540
- # A concurrent request took the slug first. Try again.
541
- continue
528
+ return records
529
+ params = await _service_account_params(execute, agent_id, name)
530
+ # Empty when the agent does not exist.
531
+ return await execute(
532
+ _ENSURE_SERVICE_ACCOUNT_QUERY, {'id': agent_id, **params}, ['id']
533
+ )
534
+
535
+ # Fast path without the lock: most agents have an account.
536
+ records = await db.execute(
537
+ _SERVICE_ACCOUNT_QUERY, {'id': agent_id}, ['id']
538
+ )
539
+ if not records:
540
+ for attempt in range(3):
541
+ try:
542
+ records = await db.locked(
543
+ f'agent-service-account:{agent_id}', ensure
544
+ )
545
+ break
546
+ except psycopg.errors.UniqueViolation as exc:
547
+ # A concurrent request for another agent took the slug
548
+ # first. Try again.
549
+ if attempt == 2:
550
+ raise fastapi.HTTPException(
551
+ status_code=409,
552
+ detail=f'Service account slug for {name!r} is in use',
553
+ ) from exc
542
554
  if not records:
543
555
  raise fastapi.HTTPException(
544
556
  status_code=404, detail=f'Agent {name!r} not found'
@@ -893,6 +905,8 @@ async def _check_platform(
893
905
  platform.check_reference(reference)
894
906
  if settings.github_app_binding is not None:
895
907
  platform.check_reference(settings.github_app_binding, field=False)
908
+ if settings.model_key_ref is not None:
909
+ platform.check_reference(settings.model_key_ref)
896
910
  except ValueError as err:
897
911
  raise _unprocessable(str(err)) from err
898
912
  binding = settings.github_app_binding
@@ -1212,7 +1226,7 @@ async def create_agent(
1212
1226
  {
1213
1227
  **props,
1214
1228
  **await _service_account_params(
1215
- db, agent_id, snapshot.name
1229
+ db.execute, agent_id, snapshot.name
1216
1230
  ),
1217
1231
  'org_slug': org_slug,
1218
1232
  'team_id': team_id,
@@ -1293,7 +1307,6 @@ async def list_agents(
1293
1307
  async def get_agent_tool_catalog(
1294
1308
  org_slug: str,
1295
1309
  request: fastapi.Request,
1296
- db: graph.Pool,
1297
1310
  valkey_client: OptionalValkeyClient,
1298
1311
  auth: typing.Annotated[
1299
1312
  permissions.AuthContext,
@@ -1301,15 +1314,13 @@ async def get_agent_tool_catalog(
1301
1314
  ],
1302
1315
  refresh: bool = False,
1303
1316
  ) -> agent_tools.AgentToolCatalog:
1304
- """List the tools that an agent can use, in groups by server.
1317
+ """List the Imbi tools that an agent can use.
1305
1318
 
1306
- The groups are the Imbi tools and the tools of each enabled MCP
1307
- server. A server that fails gives its group with an error code in
1308
- ``error`` and no tools. The error text goes only to the log. The
1309
- catalog is kept for five minutes; ``refresh=true`` lists it again.
1310
- A refresh connects to each MCP server, so it needs
1311
- ``agent:write``. The catalog is the same in each organization,
1312
- because MCP servers are global.
1319
+ The catalog has one group, the Imbi tools. When they cannot be
1320
+ made, the group has an error code in ``error`` and no tools. The
1321
+ error text goes only to the log. The catalog is kept for five
1322
+ minutes; ``refresh=true`` lists it again and needs
1323
+ ``agent:write``. The catalog is the same in each organization.
1313
1324
 
1314
1325
  Raises:
1315
1326
  403: ``refresh=true`` and the caller does not have
@@ -1323,7 +1334,7 @@ async def get_agent_tool_catalog(
1323
1334
  detail='Permission denied: refresh needs agent:write',
1324
1335
  )
1325
1336
  return await agent_tools.get_catalog(
1326
- db, valkey_client, request.app.openapi, refresh=refresh
1337
+ valkey_client, request.app.openapi, refresh=refresh
1327
1338
  )
1328
1339
 
1329
1340