kubiya-control-plane-api 0.9.15__py3-none-any.whl

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 (479) hide show
  1. control_plane_api/LICENSE +676 -0
  2. control_plane_api/README.md +350 -0
  3. control_plane_api/__init__.py +4 -0
  4. control_plane_api/__version__.py +8 -0
  5. control_plane_api/alembic/README +1 -0
  6. control_plane_api/alembic/env.py +121 -0
  7. control_plane_api/alembic/script.py.mako +28 -0
  8. control_plane_api/alembic/versions/2613c65c3dbe_initial_database_setup.py +32 -0
  9. control_plane_api/alembic/versions/2df520d4927d_merge_heads.py +28 -0
  10. control_plane_api/alembic/versions/43abf98d6a01_add_paused_status_to_executions.py +73 -0
  11. control_plane_api/alembic/versions/6289854264cb_merge_multiple_heads.py +28 -0
  12. control_plane_api/alembic/versions/6a4d4dc3d8dc_generate_execution_transitions.py +50 -0
  13. control_plane_api/alembic/versions/87d11cf0a783_add_disconnected_status_to_worker_.py +44 -0
  14. control_plane_api/alembic/versions/add_ephemeral_queue_support.py +85 -0
  15. control_plane_api/alembic/versions/add_model_type_to_llm_models.py +31 -0
  16. control_plane_api/alembic/versions/add_plan_executions_table.py +114 -0
  17. control_plane_api/alembic/versions/add_trace_span_tables.py +154 -0
  18. control_plane_api/alembic/versions/add_user_info_to_traces.py +36 -0
  19. control_plane_api/alembic/versions/adjusting_foreign_keys.py +32 -0
  20. control_plane_api/alembic/versions/b4983d976db2_initial_tables.py +1128 -0
  21. control_plane_api/alembic/versions/d181a3b40e71_rename_custom_metadata_to_metadata_in_.py +50 -0
  22. control_plane_api/alembic/versions/df9117888e82_add_missing_columns.py +82 -0
  23. control_plane_api/alembic/versions/f25de6ad895a_missing_migrations.py +34 -0
  24. control_plane_api/alembic/versions/f71305fb69b9_fix_ephemeral_queue_deletion_foreign_key.py +54 -0
  25. control_plane_api/alembic/versions/mark_local_exec_queues_as_ephemeral.py +68 -0
  26. control_plane_api/alembic.ini +148 -0
  27. control_plane_api/api/index.py +12 -0
  28. control_plane_api/app/__init__.py +11 -0
  29. control_plane_api/app/activities/__init__.py +20 -0
  30. control_plane_api/app/activities/agent_activities.py +384 -0
  31. control_plane_api/app/activities/plan_generation_activities.py +499 -0
  32. control_plane_api/app/activities/team_activities.py +424 -0
  33. control_plane_api/app/activities/temporal_cloud_activities.py +588 -0
  34. control_plane_api/app/config/__init__.py +35 -0
  35. control_plane_api/app/config/api_config.py +469 -0
  36. control_plane_api/app/config/config_loader.py +224 -0
  37. control_plane_api/app/config/model_pricing.py +323 -0
  38. control_plane_api/app/config/storage_config.py +159 -0
  39. control_plane_api/app/config.py +115 -0
  40. control_plane_api/app/controllers/__init__.py +0 -0
  41. control_plane_api/app/controllers/execution_environment_controller.py +1315 -0
  42. control_plane_api/app/database.py +135 -0
  43. control_plane_api/app/exceptions.py +408 -0
  44. control_plane_api/app/lib/__init__.py +11 -0
  45. control_plane_api/app/lib/environment.py +65 -0
  46. control_plane_api/app/lib/event_bus/__init__.py +17 -0
  47. control_plane_api/app/lib/event_bus/base.py +136 -0
  48. control_plane_api/app/lib/event_bus/manager.py +335 -0
  49. control_plane_api/app/lib/event_bus/providers/__init__.py +6 -0
  50. control_plane_api/app/lib/event_bus/providers/http_provider.py +166 -0
  51. control_plane_api/app/lib/event_bus/providers/nats_provider.py +324 -0
  52. control_plane_api/app/lib/event_bus/providers/redis_provider.py +233 -0
  53. control_plane_api/app/lib/event_bus/providers/websocket_provider.py +497 -0
  54. control_plane_api/app/lib/job_executor.py +330 -0
  55. control_plane_api/app/lib/kubiya_client.py +293 -0
  56. control_plane_api/app/lib/litellm_pricing.py +166 -0
  57. control_plane_api/app/lib/mcp_validation.py +163 -0
  58. control_plane_api/app/lib/nats/__init__.py +13 -0
  59. control_plane_api/app/lib/nats/credentials_manager.py +288 -0
  60. control_plane_api/app/lib/nats/listener.py +374 -0
  61. control_plane_api/app/lib/planning_prompt_builder.py +153 -0
  62. control_plane_api/app/lib/planning_tools/__init__.py +41 -0
  63. control_plane_api/app/lib/planning_tools/agents.py +409 -0
  64. control_plane_api/app/lib/planning_tools/agno_toolkit.py +836 -0
  65. control_plane_api/app/lib/planning_tools/base.py +119 -0
  66. control_plane_api/app/lib/planning_tools/cognitive_memory_tools.py +403 -0
  67. control_plane_api/app/lib/planning_tools/context_graph_tools.py +545 -0
  68. control_plane_api/app/lib/planning_tools/environments.py +218 -0
  69. control_plane_api/app/lib/planning_tools/knowledge.py +204 -0
  70. control_plane_api/app/lib/planning_tools/models.py +93 -0
  71. control_plane_api/app/lib/planning_tools/planning_service.py +646 -0
  72. control_plane_api/app/lib/planning_tools/resources.py +242 -0
  73. control_plane_api/app/lib/planning_tools/teams.py +334 -0
  74. control_plane_api/app/lib/policy_enforcer_client.py +1016 -0
  75. control_plane_api/app/lib/redis_client.py +803 -0
  76. control_plane_api/app/lib/sqlalchemy_utils.py +486 -0
  77. control_plane_api/app/lib/state_transition_tools/__init__.py +7 -0
  78. control_plane_api/app/lib/state_transition_tools/execution_context.py +388 -0
  79. control_plane_api/app/lib/storage/__init__.py +20 -0
  80. control_plane_api/app/lib/storage/base_provider.py +274 -0
  81. control_plane_api/app/lib/storage/provider_factory.py +157 -0
  82. control_plane_api/app/lib/storage/vercel_blob_provider.py +468 -0
  83. control_plane_api/app/lib/supabase.py +71 -0
  84. control_plane_api/app/lib/supabase_utils.py +138 -0
  85. control_plane_api/app/lib/task_planning/__init__.py +138 -0
  86. control_plane_api/app/lib/task_planning/agent_factory.py +308 -0
  87. control_plane_api/app/lib/task_planning/agents.py +389 -0
  88. control_plane_api/app/lib/task_planning/cache.py +218 -0
  89. control_plane_api/app/lib/task_planning/entity_resolver.py +273 -0
  90. control_plane_api/app/lib/task_planning/helpers.py +293 -0
  91. control_plane_api/app/lib/task_planning/hooks.py +474 -0
  92. control_plane_api/app/lib/task_planning/models.py +503 -0
  93. control_plane_api/app/lib/task_planning/plan_validator.py +166 -0
  94. control_plane_api/app/lib/task_planning/planning_workflow.py +2911 -0
  95. control_plane_api/app/lib/task_planning/runner.py +656 -0
  96. control_plane_api/app/lib/task_planning/streaming_hook.py +213 -0
  97. control_plane_api/app/lib/task_planning/workflow.py +424 -0
  98. control_plane_api/app/lib/templating/__init__.py +88 -0
  99. control_plane_api/app/lib/templating/compiler.py +278 -0
  100. control_plane_api/app/lib/templating/engine.py +178 -0
  101. control_plane_api/app/lib/templating/parsers/__init__.py +29 -0
  102. control_plane_api/app/lib/templating/parsers/base.py +96 -0
  103. control_plane_api/app/lib/templating/parsers/env.py +85 -0
  104. control_plane_api/app/lib/templating/parsers/graph.py +112 -0
  105. control_plane_api/app/lib/templating/parsers/secret.py +87 -0
  106. control_plane_api/app/lib/templating/parsers/simple.py +81 -0
  107. control_plane_api/app/lib/templating/resolver.py +366 -0
  108. control_plane_api/app/lib/templating/types.py +214 -0
  109. control_plane_api/app/lib/templating/validator.py +201 -0
  110. control_plane_api/app/lib/temporal_client.py +232 -0
  111. control_plane_api/app/lib/temporal_credentials_cache.py +178 -0
  112. control_plane_api/app/lib/temporal_credentials_service.py +203 -0
  113. control_plane_api/app/lib/validation/__init__.py +24 -0
  114. control_plane_api/app/lib/validation/runtime_validation.py +388 -0
  115. control_plane_api/app/main.py +531 -0
  116. control_plane_api/app/middleware/__init__.py +10 -0
  117. control_plane_api/app/middleware/auth.py +645 -0
  118. control_plane_api/app/middleware/exception_handler.py +267 -0
  119. control_plane_api/app/middleware/prometheus_middleware.py +173 -0
  120. control_plane_api/app/middleware/rate_limiting.py +384 -0
  121. control_plane_api/app/middleware/request_id.py +202 -0
  122. control_plane_api/app/models/__init__.py +40 -0
  123. control_plane_api/app/models/agent.py +90 -0
  124. control_plane_api/app/models/analytics.py +206 -0
  125. control_plane_api/app/models/associations.py +107 -0
  126. control_plane_api/app/models/auth_user.py +73 -0
  127. control_plane_api/app/models/context.py +161 -0
  128. control_plane_api/app/models/custom_integration.py +99 -0
  129. control_plane_api/app/models/environment.py +64 -0
  130. control_plane_api/app/models/execution.py +125 -0
  131. control_plane_api/app/models/execution_transition.py +50 -0
  132. control_plane_api/app/models/job.py +159 -0
  133. control_plane_api/app/models/llm_model.py +78 -0
  134. control_plane_api/app/models/orchestration.py +66 -0
  135. control_plane_api/app/models/plan_execution.py +102 -0
  136. control_plane_api/app/models/presence.py +49 -0
  137. control_plane_api/app/models/project.py +61 -0
  138. control_plane_api/app/models/project_management.py +85 -0
  139. control_plane_api/app/models/session.py +29 -0
  140. control_plane_api/app/models/skill.py +155 -0
  141. control_plane_api/app/models/system_tables.py +43 -0
  142. control_plane_api/app/models/task_planning.py +372 -0
  143. control_plane_api/app/models/team.py +86 -0
  144. control_plane_api/app/models/trace.py +257 -0
  145. control_plane_api/app/models/user_profile.py +54 -0
  146. control_plane_api/app/models/worker.py +221 -0
  147. control_plane_api/app/models/workflow.py +161 -0
  148. control_plane_api/app/models/workspace.py +50 -0
  149. control_plane_api/app/observability/__init__.py +177 -0
  150. control_plane_api/app/observability/context_logging.py +475 -0
  151. control_plane_api/app/observability/decorators.py +337 -0
  152. control_plane_api/app/observability/local_span_processor.py +702 -0
  153. control_plane_api/app/observability/metrics.py +303 -0
  154. control_plane_api/app/observability/middleware.py +246 -0
  155. control_plane_api/app/observability/optional.py +115 -0
  156. control_plane_api/app/observability/tracing.py +382 -0
  157. control_plane_api/app/policies/README.md +149 -0
  158. control_plane_api/app/policies/approved_users.rego +62 -0
  159. control_plane_api/app/policies/business_hours.rego +51 -0
  160. control_plane_api/app/policies/rate_limiting.rego +100 -0
  161. control_plane_api/app/policies/tool_enforcement/README.md +336 -0
  162. control_plane_api/app/policies/tool_enforcement/bash_command_validation.rego +71 -0
  163. control_plane_api/app/policies/tool_enforcement/business_hours_enforcement.rego +82 -0
  164. control_plane_api/app/policies/tool_enforcement/mcp_tool_allowlist.rego +58 -0
  165. control_plane_api/app/policies/tool_enforcement/production_safeguards.rego +80 -0
  166. control_plane_api/app/policies/tool_enforcement/role_based_tool_access.rego +44 -0
  167. control_plane_api/app/policies/tool_restrictions.rego +86 -0
  168. control_plane_api/app/routers/__init__.py +4 -0
  169. control_plane_api/app/routers/agents.py +382 -0
  170. control_plane_api/app/routers/agents_v2.py +1598 -0
  171. control_plane_api/app/routers/analytics.py +1310 -0
  172. control_plane_api/app/routers/auth.py +59 -0
  173. control_plane_api/app/routers/client_config.py +57 -0
  174. control_plane_api/app/routers/context_graph.py +561 -0
  175. control_plane_api/app/routers/context_manager.py +577 -0
  176. control_plane_api/app/routers/custom_integrations.py +490 -0
  177. control_plane_api/app/routers/enforcer.py +132 -0
  178. control_plane_api/app/routers/environment_context.py +252 -0
  179. control_plane_api/app/routers/environments.py +761 -0
  180. control_plane_api/app/routers/execution_environment.py +847 -0
  181. control_plane_api/app/routers/executions/__init__.py +28 -0
  182. control_plane_api/app/routers/executions/router.py +286 -0
  183. control_plane_api/app/routers/executions/services/__init__.py +22 -0
  184. control_plane_api/app/routers/executions/services/demo_worker_health.py +156 -0
  185. control_plane_api/app/routers/executions/services/status_service.py +420 -0
  186. control_plane_api/app/routers/executions/services/test_worker_health.py +480 -0
  187. control_plane_api/app/routers/executions/services/worker_health.py +514 -0
  188. control_plane_api/app/routers/executions/streaming/__init__.py +22 -0
  189. control_plane_api/app/routers/executions/streaming/deduplication.py +352 -0
  190. control_plane_api/app/routers/executions/streaming/event_buffer.py +353 -0
  191. control_plane_api/app/routers/executions/streaming/event_formatter.py +964 -0
  192. control_plane_api/app/routers/executions/streaming/history_loader.py +588 -0
  193. control_plane_api/app/routers/executions/streaming/live_source.py +693 -0
  194. control_plane_api/app/routers/executions/streaming/streamer.py +849 -0
  195. control_plane_api/app/routers/executions.py +4888 -0
  196. control_plane_api/app/routers/health.py +165 -0
  197. control_plane_api/app/routers/health_v2.py +394 -0
  198. control_plane_api/app/routers/integration_templates.py +496 -0
  199. control_plane_api/app/routers/integrations.py +287 -0
  200. control_plane_api/app/routers/jobs.py +1809 -0
  201. control_plane_api/app/routers/metrics.py +517 -0
  202. control_plane_api/app/routers/models.py +82 -0
  203. control_plane_api/app/routers/models_v2.py +628 -0
  204. control_plane_api/app/routers/plan_executions.py +1481 -0
  205. control_plane_api/app/routers/plan_generation_async.py +304 -0
  206. control_plane_api/app/routers/policies.py +669 -0
  207. control_plane_api/app/routers/presence.py +234 -0
  208. control_plane_api/app/routers/projects.py +987 -0
  209. control_plane_api/app/routers/runners.py +379 -0
  210. control_plane_api/app/routers/runtimes.py +172 -0
  211. control_plane_api/app/routers/secrets.py +171 -0
  212. control_plane_api/app/routers/skills.py +1010 -0
  213. control_plane_api/app/routers/skills_definitions.py +140 -0
  214. control_plane_api/app/routers/storage.py +456 -0
  215. control_plane_api/app/routers/task_planning.py +611 -0
  216. control_plane_api/app/routers/task_queues.py +650 -0
  217. control_plane_api/app/routers/team_context.py +274 -0
  218. control_plane_api/app/routers/teams.py +1747 -0
  219. control_plane_api/app/routers/templates.py +248 -0
  220. control_plane_api/app/routers/traces.py +571 -0
  221. control_plane_api/app/routers/websocket_client.py +479 -0
  222. control_plane_api/app/routers/websocket_executions_status.py +437 -0
  223. control_plane_api/app/routers/websocket_gateway.py +323 -0
  224. control_plane_api/app/routers/websocket_traces.py +576 -0
  225. control_plane_api/app/routers/worker_queues.py +2555 -0
  226. control_plane_api/app/routers/worker_websocket.py +419 -0
  227. control_plane_api/app/routers/workers.py +1004 -0
  228. control_plane_api/app/routers/workflows.py +204 -0
  229. control_plane_api/app/runtimes/__init__.py +6 -0
  230. control_plane_api/app/runtimes/validation.py +344 -0
  231. control_plane_api/app/schemas/__init__.py +1 -0
  232. control_plane_api/app/schemas/job_schemas.py +302 -0
  233. control_plane_api/app/schemas/mcp_schemas.py +311 -0
  234. control_plane_api/app/schemas/template_schemas.py +133 -0
  235. control_plane_api/app/schemas/trace_schemas.py +168 -0
  236. control_plane_api/app/schemas/worker_queue_observability_schemas.py +165 -0
  237. control_plane_api/app/services/__init__.py +1 -0
  238. control_plane_api/app/services/agno_planning_strategy.py +233 -0
  239. control_plane_api/app/services/agno_service.py +838 -0
  240. control_plane_api/app/services/claude_code_planning_service.py +203 -0
  241. control_plane_api/app/services/context_graph_client.py +224 -0
  242. control_plane_api/app/services/custom_integration_service.py +415 -0
  243. control_plane_api/app/services/integration_resolution_service.py +345 -0
  244. control_plane_api/app/services/litellm_service.py +394 -0
  245. control_plane_api/app/services/plan_generator.py +79 -0
  246. control_plane_api/app/services/planning_strategy.py +66 -0
  247. control_plane_api/app/services/planning_strategy_factory.py +118 -0
  248. control_plane_api/app/services/policy_service.py +615 -0
  249. control_plane_api/app/services/state_transition_service.py +755 -0
  250. control_plane_api/app/services/storage_service.py +593 -0
  251. control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
  252. control_plane_api/app/services/toolsets/context_graph_skill.py +432 -0
  253. control_plane_api/app/services/trace_retention.py +354 -0
  254. control_plane_api/app/services/worker_queue_metrics_service.py +190 -0
  255. control_plane_api/app/services/workflow_cancellation_manager.py +135 -0
  256. control_plane_api/app/services/workflow_operations_service.py +611 -0
  257. control_plane_api/app/skills/__init__.py +100 -0
  258. control_plane_api/app/skills/base.py +239 -0
  259. control_plane_api/app/skills/builtin/__init__.py +37 -0
  260. control_plane_api/app/skills/builtin/agent_communication/__init__.py +8 -0
  261. control_plane_api/app/skills/builtin/agent_communication/skill.py +246 -0
  262. control_plane_api/app/skills/builtin/code_ingestion/__init__.py +4 -0
  263. control_plane_api/app/skills/builtin/code_ingestion/skill.py +267 -0
  264. control_plane_api/app/skills/builtin/cognitive_memory/__init__.py +4 -0
  265. control_plane_api/app/skills/builtin/cognitive_memory/skill.py +174 -0
  266. control_plane_api/app/skills/builtin/contextual_awareness/__init__.py +4 -0
  267. control_plane_api/app/skills/builtin/contextual_awareness/skill.py +387 -0
  268. control_plane_api/app/skills/builtin/data_visualization/__init__.py +4 -0
  269. control_plane_api/app/skills/builtin/data_visualization/skill.py +154 -0
  270. control_plane_api/app/skills/builtin/docker/__init__.py +4 -0
  271. control_plane_api/app/skills/builtin/docker/skill.py +104 -0
  272. control_plane_api/app/skills/builtin/file_generation/__init__.py +4 -0
  273. control_plane_api/app/skills/builtin/file_generation/skill.py +94 -0
  274. control_plane_api/app/skills/builtin/file_system/__init__.py +4 -0
  275. control_plane_api/app/skills/builtin/file_system/skill.py +110 -0
  276. control_plane_api/app/skills/builtin/knowledge_api/__init__.py +5 -0
  277. control_plane_api/app/skills/builtin/knowledge_api/skill.py +124 -0
  278. control_plane_api/app/skills/builtin/python/__init__.py +4 -0
  279. control_plane_api/app/skills/builtin/python/skill.py +92 -0
  280. control_plane_api/app/skills/builtin/remote_filesystem/__init__.py +5 -0
  281. control_plane_api/app/skills/builtin/remote_filesystem/skill.py +170 -0
  282. control_plane_api/app/skills/builtin/shell/__init__.py +4 -0
  283. control_plane_api/app/skills/builtin/shell/skill.py +161 -0
  284. control_plane_api/app/skills/builtin/slack/__init__.py +3 -0
  285. control_plane_api/app/skills/builtin/slack/skill.py +302 -0
  286. control_plane_api/app/skills/builtin/workflow_executor/__init__.py +4 -0
  287. control_plane_api/app/skills/builtin/workflow_executor/skill.py +469 -0
  288. control_plane_api/app/skills/business_intelligence.py +189 -0
  289. control_plane_api/app/skills/config.py +63 -0
  290. control_plane_api/app/skills/loaders/__init__.py +14 -0
  291. control_plane_api/app/skills/loaders/base.py +73 -0
  292. control_plane_api/app/skills/loaders/filesystem_loader.py +199 -0
  293. control_plane_api/app/skills/registry.py +125 -0
  294. control_plane_api/app/utils/helpers.py +12 -0
  295. control_plane_api/app/utils/workflow_executor.py +354 -0
  296. control_plane_api/app/workflows/__init__.py +11 -0
  297. control_plane_api/app/workflows/agent_execution.py +520 -0
  298. control_plane_api/app/workflows/agent_execution_with_skills.py +223 -0
  299. control_plane_api/app/workflows/namespace_provisioning.py +326 -0
  300. control_plane_api/app/workflows/plan_generation.py +254 -0
  301. control_plane_api/app/workflows/team_execution.py +442 -0
  302. control_plane_api/scripts/seed_models.py +240 -0
  303. control_plane_api/scripts/validate_existing_tool_names.py +492 -0
  304. control_plane_api/shared/__init__.py +8 -0
  305. control_plane_api/shared/version.py +17 -0
  306. control_plane_api/test_deduplication.py +274 -0
  307. control_plane_api/test_executor_deduplication_e2e.py +309 -0
  308. control_plane_api/test_job_execution_e2e.py +283 -0
  309. control_plane_api/test_real_integration.py +193 -0
  310. control_plane_api/version.py +38 -0
  311. control_plane_api/worker/__init__.py +0 -0
  312. control_plane_api/worker/activities/__init__.py +0 -0
  313. control_plane_api/worker/activities/agent_activities.py +1585 -0
  314. control_plane_api/worker/activities/approval_activities.py +234 -0
  315. control_plane_api/worker/activities/job_activities.py +199 -0
  316. control_plane_api/worker/activities/runtime_activities.py +1167 -0
  317. control_plane_api/worker/activities/skill_activities.py +282 -0
  318. control_plane_api/worker/activities/team_activities.py +479 -0
  319. control_plane_api/worker/agent_runtime_server.py +370 -0
  320. control_plane_api/worker/binary_manager.py +333 -0
  321. control_plane_api/worker/config/__init__.py +31 -0
  322. control_plane_api/worker/config/worker_config.py +273 -0
  323. control_plane_api/worker/control_plane_client.py +1491 -0
  324. control_plane_api/worker/examples/analytics_integration_example.py +362 -0
  325. control_plane_api/worker/health_monitor.py +159 -0
  326. control_plane_api/worker/metrics.py +237 -0
  327. control_plane_api/worker/models/__init__.py +1 -0
  328. control_plane_api/worker/models/error_events.py +105 -0
  329. control_plane_api/worker/models/inputs.py +89 -0
  330. control_plane_api/worker/runtimes/__init__.py +35 -0
  331. control_plane_api/worker/runtimes/agent_runtime/runtime.py +485 -0
  332. control_plane_api/worker/runtimes/agno/__init__.py +34 -0
  333. control_plane_api/worker/runtimes/agno/config.py +248 -0
  334. control_plane_api/worker/runtimes/agno/hooks.py +385 -0
  335. control_plane_api/worker/runtimes/agno/mcp_builder.py +195 -0
  336. control_plane_api/worker/runtimes/agno/runtime.py +1063 -0
  337. control_plane_api/worker/runtimes/agno/utils.py +163 -0
  338. control_plane_api/worker/runtimes/base.py +979 -0
  339. control_plane_api/worker/runtimes/claude_code/__init__.py +38 -0
  340. control_plane_api/worker/runtimes/claude_code/cleanup.py +184 -0
  341. control_plane_api/worker/runtimes/claude_code/client_pool.py +529 -0
  342. control_plane_api/worker/runtimes/claude_code/config.py +829 -0
  343. control_plane_api/worker/runtimes/claude_code/hooks.py +482 -0
  344. control_plane_api/worker/runtimes/claude_code/litellm_proxy.py +1702 -0
  345. control_plane_api/worker/runtimes/claude_code/mcp_builder.py +467 -0
  346. control_plane_api/worker/runtimes/claude_code/mcp_discovery.py +558 -0
  347. control_plane_api/worker/runtimes/claude_code/runtime.py +1546 -0
  348. control_plane_api/worker/runtimes/claude_code/tool_mapper.py +403 -0
  349. control_plane_api/worker/runtimes/claude_code/utils.py +149 -0
  350. control_plane_api/worker/runtimes/factory.py +173 -0
  351. control_plane_api/worker/runtimes/model_utils.py +107 -0
  352. control_plane_api/worker/runtimes/validation.py +93 -0
  353. control_plane_api/worker/services/__init__.py +1 -0
  354. control_plane_api/worker/services/agent_communication_tools.py +908 -0
  355. control_plane_api/worker/services/agent_executor.py +485 -0
  356. control_plane_api/worker/services/agent_executor_v2.py +793 -0
  357. control_plane_api/worker/services/analytics_collector.py +457 -0
  358. control_plane_api/worker/services/analytics_service.py +464 -0
  359. control_plane_api/worker/services/approval_tools.py +310 -0
  360. control_plane_api/worker/services/approval_tools_agno.py +207 -0
  361. control_plane_api/worker/services/cancellation_manager.py +177 -0
  362. control_plane_api/worker/services/code_ingestion_tools.py +465 -0
  363. control_plane_api/worker/services/contextual_awareness_tools.py +405 -0
  364. control_plane_api/worker/services/data_visualization.py +834 -0
  365. control_plane_api/worker/services/event_publisher.py +531 -0
  366. control_plane_api/worker/services/jira_tools.py +257 -0
  367. control_plane_api/worker/services/remote_filesystem_tools.py +498 -0
  368. control_plane_api/worker/services/runtime_analytics.py +328 -0
  369. control_plane_api/worker/services/session_service.py +365 -0
  370. control_plane_api/worker/services/skill_context_enhancement.py +181 -0
  371. control_plane_api/worker/services/skill_factory.py +471 -0
  372. control_plane_api/worker/services/system_prompt_enhancement.py +410 -0
  373. control_plane_api/worker/services/team_executor.py +715 -0
  374. control_plane_api/worker/services/team_executor_v2.py +1866 -0
  375. control_plane_api/worker/services/tool_enforcement.py +254 -0
  376. control_plane_api/worker/services/workflow_executor/__init__.py +52 -0
  377. control_plane_api/worker/services/workflow_executor/event_processor.py +287 -0
  378. control_plane_api/worker/services/workflow_executor/event_publisher.py +210 -0
  379. control_plane_api/worker/services/workflow_executor/executors/__init__.py +15 -0
  380. control_plane_api/worker/services/workflow_executor/executors/base.py +270 -0
  381. control_plane_api/worker/services/workflow_executor/executors/json_executor.py +50 -0
  382. control_plane_api/worker/services/workflow_executor/executors/python_executor.py +50 -0
  383. control_plane_api/worker/services/workflow_executor/models.py +142 -0
  384. control_plane_api/worker/services/workflow_executor_tools.py +1748 -0
  385. control_plane_api/worker/skills/__init__.py +12 -0
  386. control_plane_api/worker/skills/builtin/context_graph_search/README.md +213 -0
  387. control_plane_api/worker/skills/builtin/context_graph_search/__init__.py +5 -0
  388. control_plane_api/worker/skills/builtin/context_graph_search/agno_impl.py +808 -0
  389. control_plane_api/worker/skills/builtin/context_graph_search/skill.yaml +67 -0
  390. control_plane_api/worker/skills/builtin/contextual_awareness/__init__.py +4 -0
  391. control_plane_api/worker/skills/builtin/contextual_awareness/agno_impl.py +62 -0
  392. control_plane_api/worker/skills/builtin/data_visualization/agno_impl.py +18 -0
  393. control_plane_api/worker/skills/builtin/data_visualization/skill.yaml +84 -0
  394. control_plane_api/worker/skills/builtin/docker/agno_impl.py +65 -0
  395. control_plane_api/worker/skills/builtin/docker/skill.yaml +60 -0
  396. control_plane_api/worker/skills/builtin/file_generation/agno_impl.py +47 -0
  397. control_plane_api/worker/skills/builtin/file_generation/skill.yaml +64 -0
  398. control_plane_api/worker/skills/builtin/file_system/agno_impl.py +32 -0
  399. control_plane_api/worker/skills/builtin/file_system/skill.yaml +54 -0
  400. control_plane_api/worker/skills/builtin/knowledge_api/__init__.py +4 -0
  401. control_plane_api/worker/skills/builtin/knowledge_api/agno_impl.py +50 -0
  402. control_plane_api/worker/skills/builtin/knowledge_api/skill.yaml +66 -0
  403. control_plane_api/worker/skills/builtin/python/agno_impl.py +25 -0
  404. control_plane_api/worker/skills/builtin/python/skill.yaml +60 -0
  405. control_plane_api/worker/skills/builtin/schema_fix_mixin.py +260 -0
  406. control_plane_api/worker/skills/builtin/shell/agno_impl.py +31 -0
  407. control_plane_api/worker/skills/builtin/shell/skill.yaml +60 -0
  408. control_plane_api/worker/skills/builtin/slack/__init__.py +3 -0
  409. control_plane_api/worker/skills/builtin/slack/agno_impl.py +1282 -0
  410. control_plane_api/worker/skills/builtin/slack/skill.yaml +276 -0
  411. control_plane_api/worker/skills/builtin/workflow_executor/agno_impl.py +62 -0
  412. control_plane_api/worker/skills/builtin/workflow_executor/skill.yaml +79 -0
  413. control_plane_api/worker/skills/loaders/__init__.py +5 -0
  414. control_plane_api/worker/skills/loaders/base.py +23 -0
  415. control_plane_api/worker/skills/loaders/filesystem_loader.py +357 -0
  416. control_plane_api/worker/skills/registry.py +208 -0
  417. control_plane_api/worker/tests/__init__.py +1 -0
  418. control_plane_api/worker/tests/conftest.py +12 -0
  419. control_plane_api/worker/tests/e2e/__init__.py +0 -0
  420. control_plane_api/worker/tests/e2e/test_context_graph_real_api.py +338 -0
  421. control_plane_api/worker/tests/e2e/test_context_graph_templates_e2e.py +523 -0
  422. control_plane_api/worker/tests/e2e/test_enforcement_e2e.py +344 -0
  423. control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
  424. control_plane_api/worker/tests/e2e/test_single_execution_mode.py +656 -0
  425. control_plane_api/worker/tests/integration/__init__.py +0 -0
  426. control_plane_api/worker/tests/integration/test_builtin_skills_fixes.py +245 -0
  427. control_plane_api/worker/tests/integration/test_context_graph_search_integration.py +365 -0
  428. control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
  429. control_plane_api/worker/tests/integration/test_hook_enforcement_integration.py +579 -0
  430. control_plane_api/worker/tests/integration/test_scheduled_job_workflow.py +237 -0
  431. control_plane_api/worker/tests/integration/test_system_prompt_enhancement_integration.py +343 -0
  432. control_plane_api/worker/tests/unit/__init__.py +0 -0
  433. control_plane_api/worker/tests/unit/test_builtin_skill_autoload.py +396 -0
  434. control_plane_api/worker/tests/unit/test_context_graph_search.py +450 -0
  435. control_plane_api/worker/tests/unit/test_context_graph_templates.py +403 -0
  436. control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
  437. control_plane_api/worker/tests/unit/test_control_plane_client_jobs.py +345 -0
  438. control_plane_api/worker/tests/unit/test_job_activities.py +353 -0
  439. control_plane_api/worker/tests/unit/test_skill_context_enhancement.py +321 -0
  440. control_plane_api/worker/tests/unit/test_system_prompt_enhancement.py +415 -0
  441. control_plane_api/worker/tests/unit/test_tool_enforcement.py +324 -0
  442. control_plane_api/worker/utils/__init__.py +1 -0
  443. control_plane_api/worker/utils/chunk_batcher.py +330 -0
  444. control_plane_api/worker/utils/environment.py +65 -0
  445. control_plane_api/worker/utils/error_publisher.py +260 -0
  446. control_plane_api/worker/utils/event_batcher.py +256 -0
  447. control_plane_api/worker/utils/logging_config.py +335 -0
  448. control_plane_api/worker/utils/logging_helper.py +326 -0
  449. control_plane_api/worker/utils/parameter_validator.py +120 -0
  450. control_plane_api/worker/utils/retry_utils.py +60 -0
  451. control_plane_api/worker/utils/streaming_utils.py +665 -0
  452. control_plane_api/worker/utils/tool_validation.py +332 -0
  453. control_plane_api/worker/utils/workspace_manager.py +163 -0
  454. control_plane_api/worker/websocket_client.py +393 -0
  455. control_plane_api/worker/worker.py +1297 -0
  456. control_plane_api/worker/workflows/__init__.py +0 -0
  457. control_plane_api/worker/workflows/agent_execution.py +909 -0
  458. control_plane_api/worker/workflows/scheduled_job_wrapper.py +332 -0
  459. control_plane_api/worker/workflows/team_execution.py +611 -0
  460. kubiya_control_plane_api-0.9.15.dist-info/METADATA +354 -0
  461. kubiya_control_plane_api-0.9.15.dist-info/RECORD +479 -0
  462. kubiya_control_plane_api-0.9.15.dist-info/WHEEL +5 -0
  463. kubiya_control_plane_api-0.9.15.dist-info/entry_points.txt +5 -0
  464. kubiya_control_plane_api-0.9.15.dist-info/licenses/LICENSE +676 -0
  465. kubiya_control_plane_api-0.9.15.dist-info/top_level.txt +3 -0
  466. scripts/__init__.py +1 -0
  467. scripts/migrations.py +39 -0
  468. scripts/seed_worker_queues.py +128 -0
  469. scripts/setup_agent_runtime.py +142 -0
  470. worker_internal/__init__.py +1 -0
  471. worker_internal/planner/__init__.py +1 -0
  472. worker_internal/planner/activities.py +1499 -0
  473. worker_internal/planner/agent_tools.py +197 -0
  474. worker_internal/planner/event_models.py +148 -0
  475. worker_internal/planner/event_publisher.py +67 -0
  476. worker_internal/planner/models.py +199 -0
  477. worker_internal/planner/retry_logic.py +134 -0
  478. worker_internal/planner/worker.py +300 -0
  479. worker_internal/planner/workflows.py +970 -0
@@ -0,0 +1,136 @@
1
+ """Base classes and interfaces for event bus providers."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Dict, Any, Optional, Callable
5
+ from pydantic import BaseModel, Field
6
+ import structlog
7
+
8
+ logger = structlog.get_logger(__name__)
9
+
10
+
11
+ class EventBusConfig(BaseModel):
12
+ """Base configuration for event bus providers."""
13
+
14
+ enabled: bool = Field(default=True, description="Whether this provider is enabled")
15
+ timeout_seconds: int = Field(
16
+ default=30, description="Timeout for operations in seconds"
17
+ )
18
+ retry_attempts: int = Field(
19
+ default=3, description="Number of retry attempts on failure"
20
+ )
21
+ retry_backoff_seconds: float = Field(
22
+ default=0.5, description="Backoff time between retries in seconds"
23
+ )
24
+
25
+
26
+ class EventBusProvider(ABC):
27
+ """Abstract base class for event bus providers."""
28
+
29
+ def __init__(self, config: EventBusConfig):
30
+ self.config = config
31
+ self.logger = structlog.get_logger(
32
+ __name__, provider=self.__class__.__name__
33
+ )
34
+
35
+ @abstractmethod
36
+ async def initialize(self) -> None:
37
+ """
38
+ Initialize provider connection/resources.
39
+
40
+ Raises:
41
+ Exception: If initialization fails
42
+ """
43
+ pass
44
+
45
+ @abstractmethod
46
+ async def publish_event(
47
+ self,
48
+ execution_id: str,
49
+ event_type: str,
50
+ data: Dict[str, Any],
51
+ metadata: Optional[Dict[str, Any]] = None,
52
+ ) -> bool:
53
+ """
54
+ Publish event to the bus.
55
+
56
+ Args:
57
+ execution_id: Unique execution identifier
58
+ event_type: Type of event (e.g., "message_chunk", "tool_started")
59
+ data: Event payload data
60
+ metadata: Optional metadata (organization_id, worker_id, etc.)
61
+
62
+ Returns:
63
+ True if successful, False otherwise
64
+ """
65
+ pass
66
+
67
+ @abstractmethod
68
+ async def subscribe(
69
+ self, pattern: str, callback: Callable[[Dict[str, Any]], None]
70
+ ) -> None:
71
+ """
72
+ Subscribe to events matching pattern.
73
+
74
+ Args:
75
+ pattern: Pattern to match events (provider-specific format)
76
+ callback: Async callback function to handle events
77
+ """
78
+ pass
79
+
80
+ @abstractmethod
81
+ async def health_check(self) -> Dict[str, Any]:
82
+ """
83
+ Check provider health status.
84
+
85
+ Returns:
86
+ Dict with health info: {"healthy": bool, "details": {...}}
87
+ """
88
+ pass
89
+
90
+ @abstractmethod
91
+ async def shutdown(self) -> None:
92
+ """Cleanup resources and close connections."""
93
+ pass
94
+
95
+ async def _retry_operation(
96
+ self, operation: Callable, operation_name: str
97
+ ) -> Any:
98
+ """
99
+ Retry an operation with exponential backoff.
100
+
101
+ Args:
102
+ operation: Async operation to retry
103
+ operation_name: Name for logging
104
+
105
+ Returns:
106
+ Result of operation
107
+
108
+ Raises:
109
+ Last exception if all retries fail
110
+ """
111
+ import asyncio
112
+
113
+ last_exception = None
114
+ for attempt in range(self.config.retry_attempts):
115
+ try:
116
+ return await operation()
117
+ except Exception as e:
118
+ last_exception = e
119
+ if attempt < self.config.retry_attempts - 1:
120
+ backoff = self.config.retry_backoff_seconds * (2**attempt)
121
+ self.logger.warning(
122
+ f"{operation_name}_retry",
123
+ attempt=attempt + 1,
124
+ max_attempts=self.config.retry_attempts,
125
+ backoff_seconds=backoff,
126
+ error=str(e),
127
+ )
128
+ await asyncio.sleep(backoff)
129
+ else:
130
+ self.logger.error(
131
+ f"{operation_name}_failed_all_retries",
132
+ attempts=self.config.retry_attempts,
133
+ error=str(e),
134
+ )
135
+
136
+ raise last_exception
@@ -0,0 +1,335 @@
1
+ """Event bus manager for orchestrating multiple providers."""
2
+
3
+ from typing import Dict, Any, Optional
4
+ from pydantic import BaseModel, Field
5
+ import asyncio
6
+ import structlog
7
+
8
+ from control_plane_api.app.lib.event_bus.base import EventBusProvider
9
+
10
+ logger = structlog.get_logger(__name__)
11
+
12
+
13
+ class EventBusManagerConfig(BaseModel):
14
+ """Configuration for event bus manager with all providers."""
15
+
16
+ # Import provider configs (will be defined in provider modules)
17
+ http: Optional[Any] = Field(default=None, description="HTTP provider config")
18
+ websocket: Optional[Any] = Field(
19
+ default=None, description="WebSocket provider config"
20
+ )
21
+ redis: Optional[Any] = Field(default=None, description="Redis provider config")
22
+ nats: Optional[Any] = Field(default=None, description="NATS provider config")
23
+
24
+
25
+ class EventBusManager:
26
+ """
27
+ Manages multiple event bus providers with fallback support.
28
+ Publishes to all enabled providers simultaneously.
29
+ """
30
+
31
+ def __init__(self, config: EventBusManagerConfig):
32
+ self.config = config
33
+ self.providers: Dict[str, EventBusProvider] = {}
34
+ self.logger = structlog.get_logger(__name__)
35
+ self._initialized = False
36
+
37
+ async def initialize(self) -> None:
38
+ """Initialize all enabled providers."""
39
+ if self._initialized:
40
+ self.logger.warning("event_bus_manager_already_initialized")
41
+ return
42
+
43
+ initialized_providers = []
44
+
45
+ # HTTP Provider
46
+ if self.config.http and self.config.http.enabled:
47
+ try:
48
+ from control_plane_api.app.lib.event_bus.providers.http_provider import (
49
+ HTTPEventProvider,
50
+ )
51
+
52
+ self.providers["http"] = HTTPEventProvider(self.config.http)
53
+ await self.providers["http"].initialize()
54
+ initialized_providers.append("http")
55
+ self.logger.info("http_provider_initialized")
56
+ except Exception as e:
57
+ self.logger.error("http_provider_init_failed", error=str(e))
58
+ # HTTP is critical, re-raise
59
+ raise
60
+
61
+ # WebSocket Provider
62
+ if self.config.websocket and self.config.websocket.enabled:
63
+ try:
64
+ from control_plane_api.app.lib.event_bus.providers.websocket_provider import (
65
+ WebSocketEventProvider,
66
+ )
67
+
68
+ self.providers["websocket"] = WebSocketEventProvider(
69
+ self.config.websocket
70
+ )
71
+ await self.providers["websocket"].initialize()
72
+ initialized_providers.append("websocket")
73
+ self.logger.info("websocket_provider_initialized")
74
+ except Exception as e:
75
+ self.logger.warning(
76
+ "websocket_provider_init_failed_continuing", error=str(e)
77
+ )
78
+ # WebSocket is optional, continue without it
79
+
80
+ # Redis Provider
81
+ if self.config.redis and self.config.redis.enabled:
82
+ try:
83
+ from control_plane_api.app.lib.event_bus.providers.redis_provider import (
84
+ RedisEventProvider,
85
+ )
86
+
87
+ self.providers["redis"] = RedisEventProvider(self.config.redis)
88
+ await self.providers["redis"].initialize()
89
+ initialized_providers.append("redis")
90
+ self.logger.info("redis_provider_initialized")
91
+ except Exception as e:
92
+ self.logger.warning(
93
+ "redis_provider_init_failed_continuing", error=str(e)
94
+ )
95
+ # Redis is optional, continue without it
96
+
97
+ # NATS Provider (Optional)
98
+ if self.config.nats and self.config.nats.enabled:
99
+ try:
100
+ from control_plane_api.app.lib.event_bus.providers.nats_provider import (
101
+ NATSEventProvider,
102
+ )
103
+
104
+ self.providers["nats"] = NATSEventProvider(self.config.nats)
105
+ await self.providers["nats"].initialize()
106
+ initialized_providers.append("nats")
107
+ self.logger.info("nats_provider_initialized")
108
+ except Exception as e:
109
+ self.logger.warning(
110
+ "nats_provider_init_failed_optional", error=str(e)
111
+ )
112
+ # NATS is optional, continue without it
113
+
114
+ if not self.providers:
115
+ raise RuntimeError("No event bus providers initialized")
116
+
117
+ self._initialized = True
118
+ self.logger.info(
119
+ "event_bus_manager_initialized",
120
+ providers=initialized_providers,
121
+ count=len(self.providers),
122
+ )
123
+
124
+ async def publish_event(
125
+ self,
126
+ execution_id: str,
127
+ event_type: str,
128
+ data: Dict[str, Any],
129
+ metadata: Optional[Dict[str, Any]] = None,
130
+ ) -> Dict[str, bool]:
131
+ """
132
+ Publish event to all enabled providers in parallel.
133
+
134
+ Args:
135
+ execution_id: Unique execution identifier
136
+ event_type: Type of event
137
+ data: Event payload
138
+ metadata: Optional metadata
139
+
140
+ Returns:
141
+ Dict mapping provider name to success status
142
+ """
143
+ if not self._initialized:
144
+ self.logger.error("event_bus_manager_not_initialized")
145
+ return {}
146
+
147
+ # Log start of publishing
148
+ self.logger.info(
149
+ "event_bus_publishing_start",
150
+ execution_id=execution_id,
151
+ event_type=event_type,
152
+ providers=list(self.providers.keys()),
153
+ provider_count=len(self.providers)
154
+ )
155
+
156
+ # PERFORMANCE OPTIMIZATION: Prioritize WebSocket for instant delivery
157
+ # Other providers (Redis, HTTP) run in background without blocking
158
+ websocket_task = None
159
+ websocket_name = None
160
+ background_tasks = []
161
+ background_names = []
162
+
163
+ for name, provider in self.providers.items():
164
+ task = asyncio.create_task(
165
+ provider.publish_event(execution_id, event_type, data, metadata)
166
+ )
167
+ if name == "websocket":
168
+ websocket_task = task
169
+ websocket_name = name
170
+ else:
171
+ background_tasks.append(task)
172
+ background_names.append(name)
173
+
174
+ results = {}
175
+
176
+ # Wait only for WebSocket (real-time delivery to client)
177
+ if websocket_task:
178
+ try:
179
+ ws_result = await websocket_task
180
+ results[websocket_name] = ws_result
181
+ if ws_result:
182
+ self.logger.debug(
183
+ "websocket_publish_success",
184
+ execution_id=execution_id,
185
+ event_type=event_type
186
+ )
187
+ else:
188
+ self.logger.warning(
189
+ "websocket_publish_failed",
190
+ execution_id=execution_id,
191
+ event_type=event_type
192
+ )
193
+ except Exception as e:
194
+ self.logger.error(
195
+ "websocket_publish_exception",
196
+ provider=websocket_name,
197
+ error=str(e),
198
+ execution_id=execution_id,
199
+ event_type=event_type,
200
+ )
201
+ results[websocket_name] = False
202
+
203
+ # Background providers - don't await, let them complete asynchronously
204
+ # Use asyncio.gather with return_exceptions to prevent unhandled exception warnings
205
+ if background_tasks:
206
+ async def process_background_providers():
207
+ try:
208
+ bg_results = await asyncio.gather(*background_tasks, return_exceptions=True)
209
+ for name, result in zip(background_names, bg_results):
210
+ if isinstance(result, Exception):
211
+ self.logger.warning(
212
+ "background_provider_publish_exception",
213
+ provider=name,
214
+ error=str(result),
215
+ execution_id=execution_id,
216
+ event_type=event_type,
217
+ )
218
+ elif not result:
219
+ self.logger.warning(
220
+ "background_provider_publish_failed",
221
+ provider=name,
222
+ execution_id=execution_id,
223
+ event_type=event_type
224
+ )
225
+ except Exception as e:
226
+ self.logger.error(
227
+ "background_providers_gather_failed",
228
+ error=str(e),
229
+ execution_id=execution_id,
230
+ )
231
+
232
+ # Fire and forget - schedule but don't await
233
+ asyncio.create_task(process_background_providers())
234
+
235
+ # Mark background providers as pending (we won't wait for results)
236
+ for name in background_names:
237
+ results[name] = True # Optimistically assume success
238
+
239
+ # Log overall status
240
+ success_count = sum(1 for success in results.values() if success)
241
+ if success_count == 0:
242
+ self.logger.error(
243
+ "event_bus_all_providers_failed",
244
+ execution_id=execution_id,
245
+ event_type=event_type,
246
+ results=results,
247
+ )
248
+ elif success_count < len(results):
249
+ self.logger.warning(
250
+ "event_bus_partial_success",
251
+ execution_id=execution_id,
252
+ event_type=event_type,
253
+ success_count=success_count,
254
+ total_count=len(results),
255
+ results=results,
256
+ )
257
+ else:
258
+ self.logger.info(
259
+ "event_bus_all_providers_success",
260
+ execution_id=execution_id,
261
+ event_type=event_type,
262
+ provider_count=len(results),
263
+ providers=list(results.keys())
264
+ )
265
+
266
+ return results
267
+
268
+ async def health_check(self) -> Dict[str, Any]:
269
+ """
270
+ Check health of all providers.
271
+
272
+ Returns:
273
+ Dict with health status for each provider
274
+ """
275
+ health = {}
276
+
277
+ for name, provider in self.providers.items():
278
+ try:
279
+ provider_health = await provider.health_check()
280
+ health[name] = provider_health
281
+ except Exception as e:
282
+ self.logger.error(
283
+ "provider_health_check_failed", provider=name, error=str(e)
284
+ )
285
+ health[name] = {"healthy": False, "error": str(e)}
286
+
287
+ # Overall status
288
+ healthy_count = sum(
289
+ 1 for h in health.values() if h.get("healthy", False)
290
+ )
291
+ health["_overall"] = {
292
+ "healthy": healthy_count > 0, # At least one provider healthy
293
+ "total_providers": len(self.providers),
294
+ "healthy_providers": healthy_count,
295
+ }
296
+
297
+ return health
298
+
299
+ async def shutdown(self) -> None:
300
+ """Shutdown all providers gracefully."""
301
+ if not self._initialized:
302
+ return
303
+
304
+ self.logger.info("shutting_down_event_bus_manager")
305
+
306
+ # Shutdown all providers in parallel
307
+ tasks = []
308
+ for name, provider in self.providers.items():
309
+ tasks.append(self._shutdown_provider(name, provider))
310
+
311
+ await asyncio.gather(*tasks, return_exceptions=True)
312
+
313
+ self.providers.clear()
314
+ self._initialized = False
315
+ self.logger.info("event_bus_manager_shutdown_complete")
316
+
317
+ async def _shutdown_provider(
318
+ self, name: str, provider: EventBusProvider
319
+ ) -> None:
320
+ """Shutdown a single provider with error handling."""
321
+ try:
322
+ await provider.shutdown()
323
+ self.logger.info("provider_shutdown", provider=name)
324
+ except Exception as e:
325
+ self.logger.error(
326
+ "provider_shutdown_failed", provider=name, error=str(e)
327
+ )
328
+
329
+ def is_initialized(self) -> bool:
330
+ """Check if manager is initialized."""
331
+ return self._initialized
332
+
333
+ def get_provider_names(self) -> list[str]:
334
+ """Get list of initialized provider names."""
335
+ return list(self.providers.keys())
@@ -0,0 +1,6 @@
1
+ """Event bus provider implementations."""
2
+
3
+ # Providers will be imported lazily by the manager to avoid circular dependencies
4
+ # and to handle optional dependencies gracefully
5
+
6
+ __all__ = []
@@ -0,0 +1,166 @@
1
+ """HTTP-based event bus provider."""
2
+
3
+ from typing import Dict, Any, Optional, Callable
4
+ from datetime import datetime
5
+ import httpx
6
+ import structlog
7
+ from pydantic import Field
8
+
9
+ from control_plane_api.app.lib.event_bus.base import EventBusProvider, EventBusConfig
10
+
11
+ logger = structlog.get_logger(__name__)
12
+
13
+
14
+ class HTTPConfig(EventBusConfig):
15
+ """Configuration for HTTP event provider."""
16
+
17
+ base_url: str = Field(..., description="Base URL for control plane API")
18
+ batching_enabled: bool = Field(
19
+ default=True, description="Enable event batching"
20
+ )
21
+ batch_window_ms: int = Field(
22
+ default=100, description="Batch window in milliseconds"
23
+ )
24
+ batch_max_size_bytes: int = Field(
25
+ default=1000, description="Maximum batch size in bytes"
26
+ )
27
+ api_key: Optional[str] = Field(
28
+ default=None, description="API key for authentication"
29
+ )
30
+
31
+
32
+ class HTTPEventProvider(EventBusProvider):
33
+ """HTTP-based event publishing (default provider)."""
34
+
35
+ def __init__(self, config: HTTPConfig):
36
+ super().__init__(config)
37
+ self.config: HTTPConfig = config
38
+ self.base_url = config.base_url.rstrip("/")
39
+ self.client: Optional[httpx.AsyncClient] = None
40
+
41
+ async def initialize(self) -> None:
42
+ """Initialize HTTP client."""
43
+ self.client = httpx.AsyncClient(
44
+ timeout=self.config.timeout_seconds,
45
+ follow_redirects=False, # Fail fast on redirects
46
+ )
47
+ self.logger.info(
48
+ "http_provider_initialized",
49
+ base_url=self.base_url,
50
+ batching_enabled=self.config.batching_enabled,
51
+ )
52
+
53
+ async def publish_event(
54
+ self,
55
+ execution_id: str,
56
+ event_type: str,
57
+ data: Dict[str, Any],
58
+ metadata: Optional[Dict[str, Any]] = None,
59
+ ) -> bool:
60
+ """
61
+ Publish event via HTTP POST.
62
+
63
+ Args:
64
+ execution_id: Execution ID
65
+ event_type: Event type
66
+ data: Event data
67
+ metadata: Optional metadata
68
+
69
+ Returns:
70
+ True if successful (202 Accepted)
71
+ """
72
+ if not self.client:
73
+ self.logger.error("http_client_not_initialized")
74
+ return False
75
+
76
+ url = f"{self.base_url}/api/v1/executions/{execution_id}/events"
77
+
78
+ payload = {
79
+ "event_type": event_type,
80
+ "data": data,
81
+ "timestamp": datetime.utcnow().isoformat(),
82
+ }
83
+
84
+ headers = {}
85
+ if self.config.api_key:
86
+ headers["Authorization"] = f"Bearer {self.config.api_key}"
87
+
88
+ try:
89
+ response = await self.client.post(url, json=payload, headers=headers)
90
+
91
+ if response.status_code == 202:
92
+ self.logger.debug(
93
+ "http_event_published",
94
+ execution_id=execution_id,
95
+ event_type=event_type,
96
+ )
97
+ return True
98
+ else:
99
+ self.logger.warning(
100
+ "http_event_publish_failed",
101
+ execution_id=execution_id,
102
+ event_type=event_type,
103
+ status_code=response.status_code,
104
+ response=response.text[:200],
105
+ )
106
+ return False
107
+
108
+ except httpx.TimeoutException:
109
+ self.logger.error(
110
+ "http_event_publish_timeout",
111
+ execution_id=execution_id,
112
+ event_type=event_type,
113
+ timeout=self.config.timeout_seconds,
114
+ )
115
+ return False
116
+ except Exception as e:
117
+ self.logger.error(
118
+ "http_event_publish_exception",
119
+ execution_id=execution_id,
120
+ event_type=event_type,
121
+ error=str(e),
122
+ )
123
+ return False
124
+
125
+ async def subscribe(
126
+ self, pattern: str, callback: Callable[[Dict[str, Any]], None]
127
+ ) -> None:
128
+ """HTTP provider does not support subscriptions."""
129
+ self.logger.warning(
130
+ "http_provider_subscribe_not_supported", pattern=pattern
131
+ )
132
+ raise NotImplementedError(
133
+ "HTTP provider does not support subscriptions"
134
+ )
135
+
136
+ async def health_check(self) -> Dict[str, Any]:
137
+ """Check HTTP client health."""
138
+ if not self.client:
139
+ return {
140
+ "healthy": False,
141
+ "error": "client_not_initialized",
142
+ }
143
+
144
+ try:
145
+ # Try to make a simple request to health endpoint
146
+ health_url = f"{self.base_url}/api/health"
147
+ response = await self.client.get(health_url, timeout=5.0)
148
+
149
+ return {
150
+ "healthy": response.status_code == 200,
151
+ "base_url": self.base_url,
152
+ "status_code": response.status_code,
153
+ }
154
+ except Exception as e:
155
+ return {
156
+ "healthy": False,
157
+ "base_url": self.base_url,
158
+ "error": str(e),
159
+ }
160
+
161
+ async def shutdown(self) -> None:
162
+ """Close HTTP client."""
163
+ if self.client:
164
+ await self.client.aclose()
165
+ self.client = None
166
+ self.logger.info("http_provider_shutdown")