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.
- {imbi_api-2.43.1 → imbi_api-2.45.0}/PKG-INFO +3 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/pyproject.toml +3 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tools.py +14 -72
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/internal_services.py +48 -4
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/seed.py +24 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/component_facts.py +11 -8
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_platform.py +9 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agents.py +53 -42
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/ai_providers.py +268 -20
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/dashboard.py +3 -5
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/harness.py +155 -154
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/mcp_servers.py +13 -270
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/organizations.py +7 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_deployments.py +97 -9
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/projects.py +143 -179
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/pull_requests.py +183 -15
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/releases.py +193 -36
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/scoring.py +14 -12
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/secret_broker.py +240 -7
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/egress.py +94 -6
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/platform.py +26 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/schemata.toml +9 -4
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/store.py +25 -11
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/tokens.py +52 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/lifespans.py +32 -7
- imbi_api-2.45.0/src/imbi/api/llm/tokens.py +109 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/assignments.py +72 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/resolution.py +2 -7
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/release_promote/service.py +70 -21
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/__init__.py +12 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/audit.py +11 -4
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/broker.py +55 -6
- imbi_api-2.45.0/src/imbi/api/secret_broker/identity.py +288 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/providers.py +71 -31
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/schemata.toml +16 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/secret_broker/store.py +61 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/settings.py +63 -1
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_internal_services.py +30 -3
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_seed.py +2 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_platform.py +7 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_tasks.py +19 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agents.py +11 -7
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_ai_providers.py +275 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_components.py +4 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_dashboard.py +7 -3
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_harness.py +0 -223
- imbi_api-2.45.0/tests/endpoints/test_harness_egress.py +951 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_harness_secrets.py +0 -246
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_mcp_servers.py +23 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_deployments.py +172 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_projects.py +98 -195
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_projects_helpers.py +5 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_pull_requests.py +113 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_releases.py +328 -4
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_secret_broker.py +228 -2
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/secret_support.py +26 -10
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_agent_platform.py +44 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_agent_tools.py +36 -153
- imbi_api-2.45.0/tests/test_ai_provider_tokens.py +116 -0
- imbi_api-2.45.0/tests/test_clickhouse_project_ids.py +40 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_lifespans.py +25 -1
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugins.py +40 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugins_assignments.py +161 -0
- imbi_api-2.45.0/tests/test_pull_request_resync_clickhouse.py +237 -0
- imbi_api-2.45.0/tests/test_pull_request_reviews_clickhouse.py +108 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_pull_requests_pending_deploy.py +6 -1
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_release_promote_service.py +69 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_secret_broker.py +62 -0
- imbi_api-2.45.0/tests/test_secret_identity.py +259 -0
- imbi_api-2.43.1/tests/endpoints/test_harness_egress.py +0 -470
- {imbi_api-2.43.1 → imbi_api-2.45.0}/.gitignore +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/README.md +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/moon.yml +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/README.md +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/log.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/schemata.toml +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/store.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/agent_tasks/sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/app.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/agent_api.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/agent_api_routes.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/authorization_codes.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/autonomous.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/local_auth.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/login_providers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/membership.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/oauth_clients.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/organizations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/password.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/permissions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/principals.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/sessions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/tokens.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/auth/totp.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/backfill_embeddings.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/blueprint_attributes.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/blueprint_compliance.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_pushed_at_repair.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_sync/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_sync/queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/commit_sync/service.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_status_repair.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sync/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sync/queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/deployment_sync/service.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/documents/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/documents/read_sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/domain/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/domain/models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/domain/scoring.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/drift.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/client.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/dependencies.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/base.html +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/base.txt +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/password_reset.html +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/password_reset.txt +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/welcome.html +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates/welcome.txt +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/email/templates.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_credentials.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_events.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_history.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_reads.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_document_scope.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_helpers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_json_fields.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_pagination.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_request_urls.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/_search_index.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/admin.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/admin_plugins.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_task_harness.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_tasks.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/agent_usage.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/ai_models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/api_keys.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/auth.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/auth_providers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/blueprints.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/client_credentials.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/comments.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/components.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_analytics.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_likes.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_presence.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_templates.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/document_versions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/documents.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/environments.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/events.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/graph_query.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/iggy_connectors.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/integrations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/link_definitions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/local_auth.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/maintenance.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/mfa.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/oauth_metadata.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/operations_log.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/plugin_edges.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/plugin_entities.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/plugins.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_analysis.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_commit_sync.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_configuration.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_incidents.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_integrations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_lifecycle.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_logs.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_plugins.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_pr_sync.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/project_types.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/prompts.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/roles.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/sa_api_keys.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/scoring_policies.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/search.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/service_accounts.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/status.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/tags.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/teams.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/uploads.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/user_activity.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/users.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/webhooks.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/workflow_runs.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/endpoints/workflows.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/entrypoint.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/graph_ids.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/graph_sql.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/auth.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/marketplaces.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/metrics.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/harness/sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/attribution.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/endpoints.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/errors.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/flows.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/host_integration.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/repository.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/resolution.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/state.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/identity/sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/iggy_metrics.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/llm/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/llm/dependencies.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/log.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/operations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/registry.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/state.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/maintenance/worker.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/mcp_test.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/middleware/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/middleware/rate_limit.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/openapi.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/orphan_releases.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/assignment_writer.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/credentials.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/installer.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/lifecycle.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/lifecycle_dispatch.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/reload.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/plugins/schemas.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/pr_sync/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/pr_sync/queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/pr_sync/service.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/prompts/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/prompts/release_notes_system.md +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/prompts/seed.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/py.typed +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/relationships.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/release_promote/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/release_promote/queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/sbom.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/scoring/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/scoring/queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/client.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/dependencies.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/thumbnails.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/storage/validation.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/user_document_orgs.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/runs.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/runtime_schemata.toml +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/schemata.toml +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/store.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/src/imbi/api/workflows/sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_authentication.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_authorization.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_encryption.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_login_providers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_membership.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_oauth_server.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_organizations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_permissions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_sessions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/auth/test_totp.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/test_client.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/test_init.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/clickhouse/test_privacy.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_audit_clickhouse.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_client.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_init.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_integration.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/email/test_templates.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_admin.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_admin_plugins.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_api.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_actions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_harness.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_log.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_task_relations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_agent_usage.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_ai_models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_api_keys.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_auth.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_auth_providers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_blueprints.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_client_credentials.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_comments.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_credentials.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_cross_org_reads.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_analytics.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_likes.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_presence.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_reads.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_reads_sql.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_templates.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_document_versions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_documents.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_environments.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_events.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_github_app_repository.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_graph_query.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_iggy_connectors.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_init.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_integrations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_json_fields.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_link_definitions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_local_auth.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_maintenance.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_mfa.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_operations_log.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_organizations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_pagination.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_plugin_label_validation.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_plugins.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_analysis.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_commit_sync.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_configuration.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_deployments_autonomous.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_incidents.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_integrations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_lifecycle.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_logs.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_plugins.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_response_surfacing.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_project_types.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_prompt_decisions.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_prompts.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_request_urls.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_roles.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_sa_api_keys.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_scoring.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_scoring_policies.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_search.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_search_index.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_service_accounts.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_service_writeback.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_status.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_tags.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_teams.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_uploads.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_user_activity.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_users.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_webhooks.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflow_run_history.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflow_runs.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflow_triggers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/endpoints/test_workflows.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/marketplaces/claude-code.json +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/sbom/npm-realistic.json +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/sbom/pypi-realistic.json +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/fixtures/sbom/tiny.json +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_endpoints.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_errors.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_flows.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_host_integration.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_repository.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_resolution.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_state.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/identity/test_sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/middleware/test_rate_limit.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/__init__.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_client.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_init.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_thumbnails.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/storage/test_validation.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/support.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_agent_task_events_e2e.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_app.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_assignment_writer.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_auth_settings.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_backfill_embeddings.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_blueprint_attributes.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_blueprint_compliance.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_blueprints.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_commit_pushed_at_repair.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_commit_sync_queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_commit_sync_service.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_component_facts.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_status_repair.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_sweeper.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_sync_queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_deployment_sync_service.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_drift.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_entrypoint.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_graph_ids.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_graph_sql.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_identity_attribution.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_iggy_metrics.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_init.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_installer.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_lifecycle_dispatch.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_log.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_operations.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_state.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_maintenance_worker.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_models.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_openapi.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_orphan_releases.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugin_schemas.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_plugins_credentials.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_pr_sync_queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_pr_sync_service.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_projects_drift_ranges.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_prompt_seed.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_sbom.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_scoring_queue.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_scoring_triggers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_secret_github_app.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_secret_providers.py +0 -0
- {imbi_api-2.43.1 → imbi_api-2.45.0}/tests/test_settings.py +0 -0
- {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.
|
|
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:
|
|
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.
|
|
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
|
-
"
|
|
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
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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'
|
|
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
|
-
|
|
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=
|
|
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(
|
|
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
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
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
|
|
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] = {
|
|
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
|
-
{'
|
|
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
|
-
{'
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
|
1317
|
+
"""List the Imbi tools that an agent can use.
|
|
1305
1318
|
|
|
1306
|
-
The
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
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
|
-
|
|
1337
|
+
valkey_client, request.app.openapi, refresh=refresh
|
|
1327
1338
|
)
|
|
1328
1339
|
|
|
1329
1340
|
|