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,382 @@
1
+ """
2
+ OpenTelemetry tracing configuration and utilities.
3
+
4
+ This module sets up the OpenTelemetry SDK with OTLP exporter support
5
+ and provides helper functions for creating spans with organizational context.
6
+ """
7
+
8
+ import structlog
9
+ from typing import Optional, Dict, Any
10
+ from contextlib import contextmanager
11
+
12
+ from opentelemetry import trace
13
+ from opentelemetry.sdk.trace import TracerProvider
14
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
15
+ from opentelemetry.sdk.resources import Resource, SERVICE_NAME, SERVICE_VERSION
16
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter as GRPCExporter
17
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter as HTTPExporter
18
+ from opentelemetry.sdk.trace.sampling import (
19
+ ParentBasedTraceIdRatio,
20
+ ParentBased,
21
+ ALWAYS_ON,
22
+ ALWAYS_OFF,
23
+ )
24
+
25
+ from control_plane_api.app.config import settings
26
+
27
+ logger = structlog.get_logger(__name__)
28
+
29
+ # Global tracer instance
30
+ _tracer: Optional[trace.Tracer] = None
31
+ _tracer_provider: Optional[TracerProvider] = None
32
+ _local_storage_processor = None # LocalStorageSpanProcessor instance
33
+
34
+
35
+ def _parse_resource_attributes() -> Dict[str, str]:
36
+ """Parse OTEL_RESOURCE_ATTRIBUTES from environment variable.
37
+
38
+ Format: "key1=value1,key2=value2"
39
+ """
40
+ attributes = {}
41
+ if settings.OTEL_RESOURCE_ATTRIBUTES:
42
+ for pair in settings.OTEL_RESOURCE_ATTRIBUTES.split(","):
43
+ if "=" in pair:
44
+ key, value = pair.split("=", 1)
45
+ attributes[key.strip()] = value.strip()
46
+ return attributes
47
+
48
+
49
+ def _create_sampler():
50
+ """Create appropriate sampler based on configuration."""
51
+ sampler_name = settings.OTEL_TRACES_SAMPLER.lower()
52
+
53
+ if sampler_name == "always_off":
54
+ return ALWAYS_OFF
55
+ elif sampler_name == "always_on":
56
+ return ALWAYS_ON
57
+ elif sampler_name == "parentbased_always_on":
58
+ return ParentBased(root=ALWAYS_ON)
59
+ elif sampler_name == "parentbased_always_off":
60
+ return ParentBased(root=ALWAYS_OFF)
61
+ elif sampler_name == "parentbased_traceidratio":
62
+ ratio = settings.OTEL_TRACES_SAMPLER_ARG or 1.0
63
+ return ParentBased(root=ParentBasedTraceIdRatio(ratio))
64
+ elif sampler_name == "traceidratio":
65
+ ratio = settings.OTEL_TRACES_SAMPLER_ARG or 1.0
66
+ return ParentBasedTraceIdRatio(ratio)
67
+ else:
68
+ logger.warning(
69
+ "unknown_sampler_type",
70
+ sampler=sampler_name,
71
+ fallback="parentbased_always_on"
72
+ )
73
+ return ParentBased(root=ALWAYS_ON)
74
+
75
+
76
+ def setup_telemetry() -> None:
77
+ """
78
+ Initialize OpenTelemetry SDK with OTLP exporter and/or local storage.
79
+
80
+ This should be called once at application startup.
81
+ If OTEL_ENABLED is False, tracing will be disabled (no-op tracer).
82
+ Local storage can work independently without external OTLP endpoint.
83
+ """
84
+ global _tracer, _tracer_provider
85
+
86
+ if not settings.OTEL_ENABLED:
87
+ logger.info("otel_disabled", reason="OTEL_ENABLED=false")
88
+ # Set no-op tracer
89
+ trace.set_tracer_provider(trace.NoOpTracerProvider())
90
+ _tracer = trace.get_tracer(__name__)
91
+ return
92
+
93
+ # Check if we have any tracing destination (external OTLP or local storage)
94
+ has_otlp_endpoint = bool(settings.OTEL_EXPORTER_OTLP_ENDPOINT)
95
+ has_local_storage = getattr(settings, 'OTEL_LOCAL_STORAGE_ENABLED', True)
96
+
97
+ if not has_otlp_endpoint and not has_local_storage:
98
+ logger.warning(
99
+ "otel_no_destination_configured",
100
+ message="Neither OTLP endpoint nor local storage enabled, tracing disabled"
101
+ )
102
+ # Set no-op tracer
103
+ trace.set_tracer_provider(trace.NoOpTracerProvider())
104
+ _tracer = trace.get_tracer(__name__)
105
+ return
106
+
107
+ try:
108
+ # Create resource with service information
109
+ resource_attributes = {
110
+ SERVICE_NAME: settings.OTEL_SERVICE_NAME,
111
+ SERVICE_VERSION: settings.api_version,
112
+ "deployment.environment": settings.environment,
113
+ }
114
+
115
+ # Add custom resource attributes from config
116
+ resource_attributes.update(_parse_resource_attributes())
117
+
118
+ resource = Resource.create(resource_attributes)
119
+
120
+ # Create sampler
121
+ sampler = _create_sampler()
122
+
123
+ # Create tracer provider
124
+ _tracer_provider = TracerProvider(resource=resource, sampler=sampler)
125
+
126
+ # Only add OTLP exporter if endpoint is configured
127
+ if has_otlp_endpoint:
128
+ # Create appropriate exporter based on protocol
129
+ if settings.OTEL_EXPORTER_OTLP_PROTOCOL == "http":
130
+ # HTTP/protobuf exporter
131
+ endpoint = settings.OTEL_EXPORTER_OTLP_ENDPOINT
132
+ if not endpoint.endswith("/v1/traces"):
133
+ endpoint = f"{endpoint}/v1/traces"
134
+ exporter = HTTPExporter(endpoint=endpoint)
135
+ logger.info(
136
+ "otel_exporter_configured",
137
+ protocol="http",
138
+ endpoint=endpoint
139
+ )
140
+ else:
141
+ # gRPC exporter (default)
142
+ exporter = GRPCExporter(
143
+ endpoint=settings.OTEL_EXPORTER_OTLP_ENDPOINT,
144
+ insecure=True # TODO: Configure TLS for production
145
+ )
146
+ logger.info(
147
+ "otel_exporter_configured",
148
+ protocol="grpc",
149
+ endpoint=settings.OTEL_EXPORTER_OTLP_ENDPOINT
150
+ )
151
+
152
+ # Add batch span processor with exporter
153
+ span_processor = BatchSpanProcessor(exporter)
154
+ _tracer_provider.add_span_processor(span_processor)
155
+ else:
156
+ logger.info(
157
+ "otel_exporter_skipped",
158
+ reason="No OTLP endpoint configured, using local storage only"
159
+ )
160
+
161
+ # Add local storage processor for observability UI
162
+ global _local_storage_processor
163
+ if has_local_storage:
164
+ try:
165
+ from control_plane_api.app.observability.local_span_processor import (
166
+ setup_local_storage_processor,
167
+ )
168
+ _local_storage_processor = setup_local_storage_processor(
169
+ _tracer_provider,
170
+ )
171
+ except Exception as e:
172
+ logger.warning(
173
+ "local_storage_processor_setup_failed",
174
+ error=str(e),
175
+ message="Continuing without local trace storage"
176
+ )
177
+
178
+ # Set global tracer provider
179
+ trace.set_tracer_provider(_tracer_provider)
180
+
181
+ # Create tracer instance
182
+ _tracer = trace.get_tracer(
183
+ instrumenting_module_name="control_plane_api",
184
+ instrumenting_library_version=settings.api_version
185
+ )
186
+
187
+ logger.info(
188
+ "otel_initialized",
189
+ service_name=settings.OTEL_SERVICE_NAME,
190
+ otlp_endpoint=settings.OTEL_EXPORTER_OTLP_ENDPOINT or "none",
191
+ otlp_protocol=settings.OTEL_EXPORTER_OTLP_PROTOCOL if has_otlp_endpoint else "disabled",
192
+ local_storage=bool(_local_storage_processor),
193
+ sampler=settings.OTEL_TRACES_SAMPLER,
194
+ sampler_arg=settings.OTEL_TRACES_SAMPLER_ARG,
195
+ )
196
+
197
+ except Exception as e:
198
+ logger.error(
199
+ "otel_initialization_failed",
200
+ error=str(e),
201
+ exc_info=True
202
+ )
203
+ # Fall back to no-op tracer on error
204
+ trace.set_tracer_provider(trace.NoOpTracerProvider())
205
+ _tracer = trace.get_tracer(__name__)
206
+
207
+
208
+ def get_tracer() -> trace.Tracer:
209
+ """Get the global tracer instance."""
210
+ global _tracer
211
+ if _tracer is None:
212
+ # Return default tracer if not initialized
213
+ return trace.get_tracer(__name__)
214
+ return _tracer
215
+
216
+
217
+ @contextmanager
218
+ def create_span_with_context(
219
+ name: str,
220
+ organization_id: Optional[str] = None,
221
+ user_id: Optional[str] = None,
222
+ user_email: Optional[str] = None,
223
+ user_name: Optional[str] = None,
224
+ user_avatar: Optional[str] = None,
225
+ execution_id: Optional[str] = None,
226
+ request_id: Optional[str] = None,
227
+ **attributes: Any,
228
+ ):
229
+ """
230
+ Create a span with standard organizational and user context.
231
+
232
+ Args:
233
+ name: Span name (e.g., "streaming.phase_1_connect")
234
+ organization_id: Organization slug (e.g., "kubiya-ai")
235
+ user_id: User UUID
236
+ user_email: User email address
237
+ user_name: User display name
238
+ user_avatar: User avatar URL
239
+ execution_id: Execution UUID (if applicable)
240
+ request_id: Request ID from middleware
241
+ **attributes: Additional span attributes
242
+
243
+ Usage:
244
+ with create_span_with_context(
245
+ "worker.registration",
246
+ organization_id="kubiya-ai",
247
+ user_id="user-123",
248
+ user_email="user@example.com",
249
+ user_name="John Doe",
250
+ worker_queue_id="queue-456"
251
+ ) as span:
252
+ # Do work
253
+ span.set_attribute("worker.id", worker_id)
254
+ """
255
+ tracer = get_tracer()
256
+
257
+ with tracer.start_as_current_span(name) as span:
258
+ # Add standard organizational context
259
+ if organization_id:
260
+ span.set_attribute("organization.id", organization_id)
261
+
262
+ if user_id:
263
+ span.set_attribute("user.id", user_id)
264
+
265
+ if user_email:
266
+ span.set_attribute("user.email", user_email)
267
+
268
+ if user_name:
269
+ span.set_attribute("user.name", user_name)
270
+
271
+ if user_avatar:
272
+ span.set_attribute("user.avatar", user_avatar)
273
+
274
+ if execution_id:
275
+ span.set_attribute("execution.id", execution_id)
276
+
277
+ if request_id:
278
+ span.set_attribute("request.id", request_id)
279
+
280
+ # Add custom attributes
281
+ for key, value in attributes.items():
282
+ if value is not None:
283
+ # Convert value to string for non-primitive types
284
+ if isinstance(value, (str, int, float, bool)):
285
+ span.set_attribute(key, value)
286
+ else:
287
+ span.set_attribute(key, str(value))
288
+
289
+ yield span
290
+
291
+
292
+ def get_current_trace_id() -> Optional[str]:
293
+ """
294
+ Get the current trace ID as a hex string.
295
+
296
+ Returns:
297
+ Trace ID in format: "4bf92f3577b34da6a3ce929d0e0e4736"
298
+ None if no active span
299
+ """
300
+ span = trace.get_current_span()
301
+ if span and span.is_recording():
302
+ trace_id = span.get_span_context().trace_id
303
+ return format(trace_id, '032x')
304
+ return None
305
+
306
+
307
+ def get_current_span_id() -> Optional[str]:
308
+ """
309
+ Get the current span ID as a hex string.
310
+
311
+ Returns:
312
+ 16-character hex string of the 64-bit span ID, or None if no active span
313
+ """
314
+ span = trace.get_current_span()
315
+ if span and span.is_recording():
316
+ span_id = span.get_span_context().span_id
317
+ return format(span_id, '016x')
318
+ return None
319
+
320
+
321
+ def add_span_event(name: str, attributes: Optional[Dict[str, Any]] = None) -> None:
322
+ """
323
+ Add an event (log) to the current span for better trace visibility.
324
+
325
+ This makes logs visible in the Jaeger UI as span events.
326
+
327
+ Args:
328
+ name: Event name (e.g., "Database query started", "LLM response received")
329
+ attributes: Optional key-value pairs with event details
330
+
331
+ Example:
332
+ add_span_event("Agent execution started", {"agent_id": "abc123", "prompt": "Deploy app"})
333
+ # ... do work ...
334
+ add_span_event("Agent execution completed", {"status": "success", "duration_ms": 1234})
335
+ """
336
+ span = trace.get_current_span()
337
+ if span and span.is_recording():
338
+ event_attrs = attributes or {}
339
+ span.add_event(name, event_attrs)
340
+
341
+
342
+ def add_span_error(error: Exception, attributes: Optional[Dict[str, Any]] = None) -> None:
343
+ """
344
+ Record an error in the current span with full context.
345
+
346
+ Args:
347
+ error: The exception that occurred
348
+ attributes: Optional additional context about the error
349
+
350
+ Example:
351
+ try:
352
+ risky_operation()
353
+ except Exception as e:
354
+ add_span_error(e, {"operation": "database_write", "table": "users"})
355
+ raise
356
+ """
357
+ span = trace.get_current_span()
358
+ if span and span.is_recording():
359
+ from opentelemetry.trace import StatusCode
360
+
361
+ span.set_status(StatusCode.ERROR, str(error))
362
+ span.record_exception(error)
363
+
364
+ if attributes:
365
+ for key, value in attributes.items():
366
+ span.set_attribute(f"error.{key}", str(value))
367
+
368
+
369
+ def shutdown_telemetry() -> None:
370
+ """
371
+ Shutdown the OpenTelemetry SDK and flush remaining spans.
372
+
373
+ This should be called during application shutdown.
374
+ """
375
+ global _tracer_provider
376
+
377
+ if _tracer_provider:
378
+ try:
379
+ _tracer_provider.shutdown()
380
+ logger.info("otel_shutdown_complete")
381
+ except Exception as e:
382
+ logger.error("otel_shutdown_failed", error=str(e), exc_info=True)
@@ -0,0 +1,149 @@
1
+ # Policy Modules for Agent Control Plane
2
+
3
+ This directory contains pre-built OPA (Open Policy Agent) policy modules written in Rego for common agent control plane operations.
4
+
5
+ ## Overview
6
+
7
+ Policies are stored and evaluated in the OPA Watchdog Enforcer Service. These modules provide templates and examples for:
8
+
9
+ - **Execution Policies**: Control when and how agents can execute
10
+ - **Resource Policies**: Limit resource usage and access
11
+ - **Time-based Policies**: Business hours and rate limiting
12
+ - **Tool Enforcement Policies**: Real-time validation of tool executions (NEW)
13
+ - **Tool Policies**: Control which tools agents can use
14
+ - **Team Policies**: Collaboration and approval workflows
15
+
16
+ ### Tool Enforcement Policies (NEW)
17
+
18
+ The `tool_enforcement/` directory contains policies for **real-time tool call enforcement** during agent execution. These policies are evaluated before each tool execution and can block or allow tools based on:
19
+
20
+ - User roles and permissions
21
+ - Tool risk level (critical/high/medium/low)
22
+ - Environment (production/staging/dev)
23
+ - Time of day (business hours)
24
+ - Tool source (MCP/builtin/skill)
25
+ - Command patterns (dangerous bash commands)
26
+
27
+ See the [Tool Enforcement Guide](../../../docs/TOOL_ENFORCEMENT.md) for detailed documentation.
28
+
29
+ ## Policy Structure
30
+
31
+ All policies follow this structure:
32
+
33
+ ```rego
34
+ package <policy_name>
35
+
36
+ # Default decision (deny by default)
37
+ default allow = false
38
+
39
+ # Rules that grant permissions
40
+ allow {
41
+ # conditions
42
+ }
43
+
44
+ # Violations that explain why requests are denied
45
+ violations[msg] {
46
+ # condition
47
+ msg := "Explanation"
48
+ }
49
+ ```
50
+
51
+ ## Policy Priority and Inheritance
52
+
53
+ Policies are associated with entities (agents, teams, environments) with automatic inheritance:
54
+
55
+ 1. **Environment** policies (priority: 300) - apply to all agents/teams in the environment
56
+ 2. **Team** policies (priority: 200) - apply to all agents in the team
57
+ 3. **Agent** policies (priority: 100) - apply to specific agent
58
+
59
+ When the same policy is defined at multiple levels, **higher priority wins**.
60
+
61
+ ## Usage
62
+
63
+ ### 1. Create a Policy
64
+
65
+ ```bash
66
+ curl -X POST https://your-control-plane.com/api/v1/policies \
67
+ -H "Authorization: Bearer $TOKEN" \
68
+ -H "Content-Type: application/json" \
69
+ -d '{
70
+ "name": "business-hours-only",
71
+ "policy_content": "<rego_policy>",
72
+ "description": "Allow executions only during business hours",
73
+ "enabled": true,
74
+ "tags": ["time", "compliance"]
75
+ }'
76
+ ```
77
+
78
+ ### 2. Associate with Entity
79
+
80
+ ```bash
81
+ curl -X POST https://your-control-plane.com/api/v1/policies/associations \
82
+ -H "Authorization: Bearer $TOKEN" \
83
+ -H "Content-Type: application/json" \
84
+ -d '{
85
+ "policy_id": "<policy_uuid>",
86
+ "policy_name": "business-hours-only",
87
+ "entity_type": "environment",
88
+ "entity_id": "<environment_uuid>",
89
+ "enabled": true
90
+ }'
91
+ ```
92
+
93
+ ### 3. Evaluate Policy
94
+
95
+ Policies are automatically evaluated during agent execution. You can also test manually:
96
+
97
+ ```bash
98
+ curl -X POST https://your-control-plane.com/api/v1/policies/evaluate/agent/<agent_id> \
99
+ -H "Authorization: Bearer $TOKEN" \
100
+ -H "Content-Type: application/json" \
101
+ -d '{
102
+ "input_data": {
103
+ "action": "execute",
104
+ "user": "alice@company.com",
105
+ "time": "2025-01-15T14:30:00Z"
106
+ }
107
+ }'
108
+ ```
109
+
110
+ ## Available Policy Modules
111
+
112
+ ### Tool Enforcement Policies (`tool_enforcement/`)
113
+
114
+ Real-time tool call validation policies:
115
+
116
+ - **`role_based_tool_access.rego`** - Restrict command execution tools to admin/devops roles
117
+ - **`production_safeguards.rego`** - Block critical/high-risk tools in production environment
118
+ - **`bash_command_validation.rego`** - Block dangerous bash patterns (rm -rf, dd, mkfs, etc.)
119
+ - **`business_hours_enforcement.rego`** - Restrict high-risk tools to business hours (9 AM - 6 PM UTC, Mon-Fri)
120
+ - **`mcp_tool_allowlist.rego`** - Whitelist approved MCP tools
121
+
122
+ All tool enforcement policies use package `kubiya.tool_enforcement` and evaluate against structured tool execution input. See [Tool Enforcement Guide](../../../docs/TOOL_ENFORCEMENT.md) for input schema and examples.
123
+
124
+ ### General Policy Modules
125
+
126
+ See individual `.rego` files for detailed policies:
127
+
128
+ - `business_hours.rego` - Restrict executions to business hours
129
+ - `approved_users.rego` - Require user approval list
130
+ - `rate_limiting.rego` - Limit execution frequency
131
+ - `resource_limits.rego` - Enforce resource quotas
132
+ - `tool_restrictions.rego` - Control tool usage
133
+ - `approval_workflow.rego` - Require approvals for sensitive actions
134
+ - `environment_restrictions.rego` - Restrict access to environments
135
+
136
+ ## Policy Development Tips
137
+
138
+ 1. **Test policies locally** using OPA CLI before deploying
139
+ 2. **Start with deny-by-default** for security
140
+ 3. **Use clear violation messages** for debugging
141
+ 4. **Document assumptions** in policy comments
142
+ 5. **Version policies** using tags or metadata
143
+ 6. **Test edge cases** thoroughly
144
+
145
+ ## References
146
+
147
+ - [OPA Documentation](https://www.openpolicyagent.org/docs/latest/)
148
+ - [Rego Language Reference](https://www.openpolicyagent.org/docs/latest/policy-reference/)
149
+ - [OPA Watchdog Enforcer API](https://enforcer-psi.vercel.app/api/docs)
@@ -0,0 +1,62 @@
1
+ # Approved Users Policy
2
+ # Only allows executions from a whitelist of approved users
3
+
4
+ package approved_users
5
+
6
+ import future.keywords.if
7
+ import future.keywords.in
8
+
9
+ # Default deny
10
+ default allow = false
11
+
12
+ # List of approved users (emails)
13
+ # This can be customized per organization or pulled from metadata
14
+ approved_user_list := {
15
+ "admin@company.com",
16
+ "devops@company.com",
17
+ "alice@company.com",
18
+ "bob@company.com"
19
+ }
20
+
21
+ # Allow if user is in the approved list
22
+ allow if {
23
+ input.user in approved_user_list
24
+ }
25
+
26
+ # Also allow if user email domain is approved
27
+ allow if {
28
+ user_email := input.user
29
+ contains(user_email, "@")
30
+ domain := split(user_email, "@")[1]
31
+ domain in approved_domains
32
+ }
33
+
34
+ # Approved email domains
35
+ approved_domains := {
36
+ "company.com",
37
+ "trusted-partner.com"
38
+ }
39
+
40
+ # Violations
41
+ violations[msg] if {
42
+ not input.user in approved_user_list
43
+ user_email := input.user
44
+ contains(user_email, "@")
45
+ domain := split(user_email, "@")[1]
46
+ not domain in approved_domains
47
+ msg := sprintf("User '%v' is not in the approved user list or approved domain", [input.user])
48
+ }
49
+
50
+ violations[msg] if {
51
+ not input.user
52
+ msg := "No user specified in the request"
53
+ }
54
+
55
+ # Metadata
56
+ metadata := {
57
+ "name": "approved-users-only",
58
+ "description": "Only allow executions from approved users or domains",
59
+ "version": "1.0.0",
60
+ "author": "Kubiya",
61
+ "tags": ["security", "access-control", "users"]
62
+ }
@@ -0,0 +1,51 @@
1
+ # Business Hours Policy
2
+ # Restricts agent executions to business hours (9 AM - 5 PM, Monday-Friday)
3
+
4
+ package business_hours
5
+
6
+ import future.keywords.if
7
+ import future.keywords.in
8
+
9
+ # Default deny
10
+ default allow = false
11
+
12
+ # Allow executions during business hours
13
+ allow if {
14
+ is_business_hours
15
+ not is_weekend
16
+ }
17
+
18
+ # Check if current time is within business hours (9 AM - 5 PM)
19
+ is_business_hours if {
20
+ time_hour := time.parse_rfc3339_ns(input.time)
21
+ hour := time.clock(time_hour)[0]
22
+ hour >= 9
23
+ hour < 17
24
+ }
25
+
26
+ # Check if current day is a weekend
27
+ is_weekend if {
28
+ time_day := time.parse_rfc3339_ns(input.time)
29
+ weekday := time.weekday(time_day)
30
+ weekday in ["Saturday", "Sunday"]
31
+ }
32
+
33
+ # Violations
34
+ violations[msg] if {
35
+ not is_business_hours
36
+ msg := sprintf("Execution requested outside business hours (9 AM - 5 PM). Current time: %v", [input.time])
37
+ }
38
+
39
+ violations[msg] if {
40
+ is_weekend
41
+ msg := sprintf("Execution requested on weekend. Current day: %v", [time.weekday(time.parse_rfc3339_ns(input.time))])
42
+ }
43
+
44
+ # Metadata
45
+ metadata := {
46
+ "name": "business-hours-only",
47
+ "description": "Restrict agent executions to business hours (9 AM - 5 PM, Monday-Friday)",
48
+ "version": "1.0.0",
49
+ "author": "Kubiya",
50
+ "tags": ["time", "compliance", "business-hours"]
51
+ }