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,577 @@
1
+ """
2
+ Unified Context Management System for Agent Control Plane.
3
+
4
+ Manages contextual settings (knowledge, resources, policies) across all entity types:
5
+ - Environments
6
+ - Teams
7
+ - Projects
8
+ - Agents
9
+
10
+ Provides layered context resolution: Environment → Team → Project → Agent
11
+ """
12
+
13
+ from fastapi import APIRouter, Depends, HTTPException, status, Request
14
+ from typing import List, Optional, Dict, Any, Literal
15
+ from datetime import datetime
16
+ from pydantic import BaseModel, Field
17
+ import structlog
18
+ import uuid
19
+
20
+ from control_plane_api.app.middleware.auth import get_current_organization
21
+ from control_plane_api.app.database import get_db
22
+ from sqlalchemy.orm import Session
23
+ from control_plane_api.app.models.context import (
24
+ AgentContext, EnvironmentContext, ProjectContext, TeamContext
25
+ )
26
+ from control_plane_api.app.models.agent import Agent
27
+ from control_plane_api.app.models.environment import Environment
28
+ from control_plane_api.app.models.project import Project
29
+ from control_plane_api.app.models.team import Team
30
+ from control_plane_api.app.models.associations import AgentEnvironment, TeamEnvironment
31
+
32
+ logger = structlog.get_logger()
33
+
34
+ router = APIRouter()
35
+
36
+ # Entity types that support context
37
+ EntityType = Literal["environment", "team", "project", "agent"]
38
+
39
+ # Pydantic schemas
40
+ class ContextData(BaseModel):
41
+ """Generic context data structure"""
42
+ knowledge_uuids: List[str] = Field(default_factory=list, description="Knowledge base UUIDs")
43
+ resource_ids: List[str] = Field(default_factory=list, description="Resource IDs from Meilisearch")
44
+ policy_ids: List[str] = Field(default_factory=list, description="OPA policy IDs")
45
+
46
+
47
+ class UpdateContextRequest(BaseModel):
48
+ """Request to update context for any entity"""
49
+ knowledge_uuids: List[str] = Field(default_factory=list)
50
+ resource_ids: List[str] = Field(default_factory=list)
51
+ policy_ids: List[str] = Field(default_factory=list)
52
+
53
+
54
+ class ContextResponse(BaseModel):
55
+ """Generic context response"""
56
+ id: str
57
+ entity_type: str
58
+ entity_id: str
59
+ organization_id: str
60
+ knowledge_uuids: List[str]
61
+ resource_ids: List[str]
62
+ policy_ids: List[str]
63
+ created_at: str
64
+ updated_at: str
65
+
66
+
67
+ class ResolvedContextResponse(BaseModel):
68
+ """Resolved context with inheritance from all layers"""
69
+ entity_id: str
70
+ entity_type: str
71
+ environment_id: Optional[str] = None
72
+ team_id: Optional[str] = None
73
+ project_id: Optional[str] = None
74
+
75
+ # Aggregated context from all layers
76
+ knowledge_uuids: List[str] = Field(description="Merged knowledge from all layers")
77
+ resource_ids: List[str] = Field(description="Merged resources from all layers")
78
+ policy_ids: List[str] = Field(description="Merged policies from all layers")
79
+
80
+ # Layer breakdown for debugging
81
+ layers: Dict[str, ContextData] = Field(description="Context breakdown by layer")
82
+
83
+
84
+ # Model mapping for context models
85
+ CONTEXT_MODEL_MAP = {
86
+ "environment": EnvironmentContext,
87
+ "team": TeamContext,
88
+ "project": ProjectContext,
89
+ "agent": AgentContext,
90
+ }
91
+
92
+ # Entity model mapping (for validation)
93
+ ENTITY_MODEL_MAP = {
94
+ "environment": Environment,
95
+ "team": Team,
96
+ "project": Project,
97
+ "agent": Agent,
98
+ }
99
+
100
+
101
+ async def _verify_entity_exists(
102
+ db: Session, entity_type: EntityType, entity_id: str, org_id: str
103
+ ) -> bool:
104
+ """Verify that an entity exists for the organization"""
105
+ entity_model = ENTITY_MODEL_MAP.get(entity_type)
106
+ if not entity_model:
107
+ return False
108
+
109
+ entity = db.query(entity_model).filter(
110
+ entity_model.id == uuid.UUID(entity_id),
111
+ entity_model.organization_id == org_id
112
+ ).first()
113
+
114
+ return entity is not None
115
+
116
+
117
+ async def _get_or_create_context(
118
+ db: Session, entity_type: EntityType, entity_id: str, org_id: str
119
+ ) -> Dict[str, Any]:
120
+ """Get existing context or create a default one"""
121
+ context_model = CONTEXT_MODEL_MAP.get(entity_type)
122
+ if not context_model:
123
+ raise ValueError(f"Invalid entity type: {entity_type}")
124
+
125
+ # Build filter dynamically based on entity type
126
+ entity_id_field = getattr(context_model, f"{entity_type}_id")
127
+
128
+ # Try to get existing context
129
+ context = db.query(context_model).filter(
130
+ entity_id_field == uuid.UUID(entity_id),
131
+ context_model.organization_id == uuid.UUID(org_id)
132
+ ).first()
133
+
134
+ if context:
135
+ # Convert to dict
136
+ return {
137
+ "id": str(context.id),
138
+ f"{entity_type}_id": str(getattr(context, f"{entity_type}_id")),
139
+ "entity_type": context.entity_type,
140
+ "organization_id": str(context.organization_id),
141
+ "knowledge_uuids": context.knowledge_uuids or [],
142
+ "resource_ids": context.resource_ids or [],
143
+ "policy_ids": context.policy_ids or [],
144
+ "created_at": context.created_at.isoformat() if context.created_at else datetime.utcnow().isoformat(),
145
+ "updated_at": context.updated_at.isoformat() if context.updated_at else datetime.utcnow().isoformat(),
146
+ }
147
+
148
+ # Create default context
149
+ context_data = {
150
+ f"{entity_type}_id": uuid.UUID(entity_id),
151
+ "entity_type": entity_type,
152
+ "organization_id": uuid.UUID(org_id),
153
+ "knowledge_uuids": [],
154
+ "resource_ids": [],
155
+ "policy_ids": [],
156
+ }
157
+
158
+ new_context = context_model(**context_data)
159
+ db.add(new_context)
160
+ db.commit()
161
+ db.refresh(new_context)
162
+
163
+ logger.info(
164
+ "context_created",
165
+ entity_type=entity_type,
166
+ entity_id=entity_id,
167
+ org_id=org_id,
168
+ )
169
+
170
+ return {
171
+ "id": str(new_context.id),
172
+ f"{entity_type}_id": str(getattr(new_context, f"{entity_type}_id")),
173
+ "entity_type": new_context.entity_type,
174
+ "organization_id": str(new_context.organization_id),
175
+ "knowledge_uuids": new_context.knowledge_uuids or [],
176
+ "resource_ids": new_context.resource_ids or [],
177
+ "policy_ids": new_context.policy_ids or [],
178
+ "created_at": new_context.created_at.isoformat() if new_context.created_at else datetime.utcnow().isoformat(),
179
+ "updated_at": new_context.updated_at.isoformat() if new_context.updated_at else datetime.utcnow().isoformat(),
180
+ }
181
+
182
+
183
+ @router.get("/context/{entity_type}/{entity_id}", response_model=ContextResponse)
184
+ async def get_context(
185
+ entity_type: EntityType,
186
+ entity_id: str,
187
+ request: Request,
188
+ organization: dict = Depends(get_current_organization),
189
+ db: Session = Depends(get_db),
190
+ ):
191
+ """Get context configuration for any entity type"""
192
+ try:
193
+ org_id = organization["id"]
194
+
195
+ # Verify entity exists
196
+ if not await _verify_entity_exists(db, entity_type, entity_id, org_id):
197
+ raise HTTPException(
198
+ status_code=status.HTTP_404_NOT_FOUND,
199
+ detail=f"{entity_type.capitalize()} not found"
200
+ )
201
+
202
+ # Get or create context
203
+ context_data = await _get_or_create_context(db, entity_type, entity_id, org_id)
204
+
205
+ return ContextResponse(**context_data)
206
+
207
+ except HTTPException:
208
+ raise
209
+ except Exception as e:
210
+ logger.error("get_context_failed", error=str(e), entity_type=entity_type, entity_id=entity_id)
211
+ raise HTTPException(
212
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
213
+ detail=f"Failed to get {entity_type} context: {str(e)}"
214
+ )
215
+
216
+
217
+ @router.put("/context/{entity_type}/{entity_id}", response_model=ContextResponse)
218
+ async def update_context(
219
+ entity_type: EntityType,
220
+ entity_id: str,
221
+ context_data: UpdateContextRequest,
222
+ request: Request,
223
+ organization: dict = Depends(get_current_organization),
224
+ db: Session = Depends(get_db),
225
+ ):
226
+ """Update context configuration for any entity type"""
227
+ try:
228
+ org_id = organization["id"]
229
+
230
+ # Verify entity exists
231
+ if not await _verify_entity_exists(db, entity_type, entity_id, org_id):
232
+ raise HTTPException(
233
+ status_code=status.HTTP_404_NOT_FOUND,
234
+ detail=f"{entity_type.capitalize()} not found"
235
+ )
236
+
237
+ context_model = CONTEXT_MODEL_MAP[entity_type]
238
+ entity_id_field = getattr(context_model, f"{entity_type}_id")
239
+
240
+ # Check if context exists
241
+ existing = db.query(context_model).filter(
242
+ entity_id_field == uuid.UUID(entity_id),
243
+ context_model.organization_id == uuid.UUID(org_id)
244
+ ).first()
245
+
246
+ if existing:
247
+ # Update existing
248
+ existing.knowledge_uuids = context_data.knowledge_uuids
249
+ existing.resource_ids = context_data.resource_ids
250
+ existing.policy_ids = context_data.policy_ids
251
+ existing.updated_at = datetime.utcnow()
252
+ db.commit()
253
+ db.refresh(existing)
254
+ context = existing
255
+ else:
256
+ # Create new
257
+ new_context_data = {
258
+ f"{entity_type}_id": uuid.UUID(entity_id),
259
+ "entity_type": entity_type,
260
+ "organization_id": uuid.UUID(org_id),
261
+ "knowledge_uuids": context_data.knowledge_uuids,
262
+ "resource_ids": context_data.resource_ids,
263
+ "policy_ids": context_data.policy_ids,
264
+ }
265
+ context = context_model(**new_context_data)
266
+ db.add(context)
267
+ db.commit()
268
+ db.refresh(context)
269
+
270
+ logger.info(
271
+ "context_updated",
272
+ entity_type=entity_type,
273
+ entity_id=entity_id,
274
+ knowledge_count=len(context_data.knowledge_uuids),
275
+ resource_count=len(context_data.resource_ids),
276
+ policy_count=len(context_data.policy_ids),
277
+ org_id=org_id,
278
+ )
279
+
280
+ return ContextResponse(
281
+ id=str(context.id),
282
+ entity_type=context.entity_type,
283
+ entity_id=str(getattr(context, f"{entity_type}_id")),
284
+ organization_id=str(context.organization_id),
285
+ knowledge_uuids=context.knowledge_uuids or [],
286
+ resource_ids=context.resource_ids or [],
287
+ policy_ids=context.policy_ids or [],
288
+ created_at=context.created_at.isoformat() if context.created_at else datetime.utcnow().isoformat(),
289
+ updated_at=context.updated_at.isoformat() if context.updated_at else datetime.utcnow().isoformat(),
290
+ )
291
+
292
+ except HTTPException:
293
+ raise
294
+ except Exception as e:
295
+ logger.error("update_context_failed", error=str(e), entity_type=entity_type, entity_id=entity_id)
296
+ raise HTTPException(
297
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
298
+ detail=f"Failed to update {entity_type} context: {str(e)}"
299
+ )
300
+
301
+
302
+ @router.delete("/context/{entity_type}/{entity_id}", status_code=status.HTTP_204_NO_CONTENT)
303
+ async def clear_context(
304
+ entity_type: EntityType,
305
+ entity_id: str,
306
+ request: Request,
307
+ organization: dict = Depends(get_current_organization),
308
+ db: Session = Depends(get_db),
309
+ ):
310
+ """Clear all context for an entity"""
311
+ try:
312
+ org_id = organization["id"]
313
+
314
+ context_model = CONTEXT_MODEL_MAP[entity_type]
315
+ entity_id_field = getattr(context_model, f"{entity_type}_id")
316
+
317
+ # Find and update the context
318
+ context = db.query(context_model).filter(
319
+ entity_id_field == uuid.UUID(entity_id),
320
+ context_model.organization_id == uuid.UUID(org_id)
321
+ ).first()
322
+
323
+ if context:
324
+ context.knowledge_uuids = []
325
+ context.resource_ids = []
326
+ context.policy_ids = []
327
+ context.updated_at = datetime.utcnow()
328
+ db.commit()
329
+
330
+ logger.info("context_cleared", entity_type=entity_type, entity_id=entity_id, org_id=org_id)
331
+ return None
332
+
333
+ except Exception as e:
334
+ logger.error("clear_context_failed", error=str(e), entity_type=entity_type, entity_id=entity_id)
335
+ raise HTTPException(
336
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
337
+ detail=f"Failed to clear {entity_type} context: {str(e)}"
338
+ )
339
+
340
+
341
+ @router.get("/context/resolve/{entity_type}/{entity_id}", response_model=ResolvedContextResponse)
342
+ async def resolve_context(
343
+ entity_type: EntityType,
344
+ entity_id: str,
345
+ request: Request,
346
+ organization: dict = Depends(get_current_organization),
347
+ db: Session = Depends(get_db),
348
+ ):
349
+ """
350
+ Resolve context with inheritance from all layers.
351
+
352
+ Resolution order (each layer adds to the previous):
353
+ 1. ALL Environments (many-to-many for agents/teams)
354
+ 2. Team (if member of a team)
355
+ 3. ALL Team Environments (if agent is part of team)
356
+ 4. Project (if assigned to a project)
357
+ 5. Agent/Entity itself
358
+
359
+ Returns merged context with full layer breakdown.
360
+ """
361
+ try:
362
+ org_id = organization["id"]
363
+
364
+ # Verify entity exists
365
+ if not await _verify_entity_exists(db, entity_type, entity_id, org_id):
366
+ raise HTTPException(
367
+ status_code=status.HTTP_404_NOT_FOUND,
368
+ detail=f"{entity_type.capitalize()} not found"
369
+ )
370
+
371
+ layers: Dict[str, ContextData] = {}
372
+ team_id: Optional[str] = None
373
+ project_id: Optional[str] = None
374
+ environment_ids: List[str] = []
375
+
376
+ # Collect context from all layers
377
+ all_knowledge: List[str] = []
378
+ all_resources: List[str] = []
379
+ all_policies: List[str] = []
380
+
381
+ # 1. Get entity relationships (team, project)
382
+ entity_model = ENTITY_MODEL_MAP[entity_type]
383
+ entity = db.query(entity_model).filter(
384
+ entity_model.id == uuid.UUID(entity_id),
385
+ entity_model.organization_id == org_id
386
+ ).first()
387
+
388
+ if not entity:
389
+ raise HTTPException(
390
+ status_code=status.HTTP_404_NOT_FOUND,
391
+ detail=f"{entity_type.capitalize()} not found"
392
+ )
393
+
394
+ # Extract relationships
395
+ team_id = str(entity.team_id) if hasattr(entity, 'team_id') and entity.team_id else None
396
+ project_id = str(entity.project_id) if hasattr(entity, 'project_id') and entity.project_id else None
397
+
398
+ # 2. Layer 1: Get ALL agent/team environments (many-to-many)
399
+ if entity_type == "agent":
400
+ # Get all agent environments
401
+ agent_envs = db.query(AgentEnvironment).filter(
402
+ AgentEnvironment.agent_id == uuid.UUID(entity_id)
403
+ ).all()
404
+ environment_ids = [str(env.environment_id) for env in agent_envs]
405
+
406
+ elif entity_type == "team":
407
+ # Get all team environments
408
+ team_envs = db.query(TeamEnvironment).filter(
409
+ TeamEnvironment.team_id == uuid.UUID(entity_id)
410
+ ).all()
411
+ environment_ids = [str(env.environment_id) for env in team_envs]
412
+
413
+ # Merge context from ALL environments
414
+ for idx, env_id in enumerate(environment_ids):
415
+ try:
416
+ env_context = await _get_or_create_context(db, "environment", env_id, org_id)
417
+ layer_key = f"environment_{idx+1}" if len(environment_ids) > 1 else "environment"
418
+ layers[layer_key] = ContextData(
419
+ knowledge_uuids=env_context.get("knowledge_uuids", []),
420
+ resource_ids=env_context.get("resource_ids", []),
421
+ policy_ids=env_context.get("policy_ids", []),
422
+ )
423
+ all_knowledge.extend(layers[layer_key].knowledge_uuids)
424
+ all_resources.extend(layers[layer_key].resource_ids)
425
+ all_policies.extend(layers[layer_key].policy_ids)
426
+ except Exception as e:
427
+ logger.warning("failed_to_get_environment_context", error=str(e), environment_id=env_id)
428
+
429
+ # 3. Layer 2: Team context
430
+ if team_id:
431
+ try:
432
+ team_context = await _get_or_create_context(db, "team", team_id, org_id)
433
+ layers["team"] = ContextData(
434
+ knowledge_uuids=team_context.get("knowledge_uuids", []),
435
+ resource_ids=team_context.get("resource_ids", []),
436
+ policy_ids=team_context.get("policy_ids", []),
437
+ )
438
+ all_knowledge.extend(layers["team"].knowledge_uuids)
439
+ all_resources.extend(layers["team"].resource_ids)
440
+ all_policies.extend(layers["team"].policy_ids)
441
+ except Exception as e:
442
+ logger.warning("failed_to_get_team_context", error=str(e), team_id=team_id)
443
+
444
+ # 3b. Get ALL team environments (if agent has team)
445
+ if entity_type == "agent":
446
+ team_envs = db.query(TeamEnvironment).filter(
447
+ TeamEnvironment.team_id == uuid.UUID(team_id)
448
+ ).all()
449
+ team_environment_ids = [str(env.environment_id) for env in team_envs]
450
+
451
+ for idx, env_id in enumerate(team_environment_ids):
452
+ # Skip if already processed in agent environments
453
+ if env_id in environment_ids:
454
+ continue
455
+ try:
456
+ env_context = await _get_or_create_context(db, "environment", env_id, org_id)
457
+ layer_key = f"team_environment_{idx+1}"
458
+ layers[layer_key] = ContextData(
459
+ knowledge_uuids=env_context.get("knowledge_uuids", []),
460
+ resource_ids=env_context.get("resource_ids", []),
461
+ policy_ids=env_context.get("policy_ids", []),
462
+ )
463
+ all_knowledge.extend(layers[layer_key].knowledge_uuids)
464
+ all_resources.extend(layers[layer_key].resource_ids)
465
+ all_policies.extend(layers[layer_key].policy_ids)
466
+ except Exception as e:
467
+ logger.warning("failed_to_get_team_environment_context", error=str(e), environment_id=env_id)
468
+
469
+ # 4. Layer 3: Project context
470
+ if project_id:
471
+ try:
472
+ project_context = await _get_or_create_context(db, "project", project_id, org_id)
473
+ layers["project"] = ContextData(
474
+ knowledge_uuids=project_context.get("knowledge_uuids", []),
475
+ resource_ids=project_context.get("resource_ids", []),
476
+ policy_ids=project_context.get("policy_ids", []),
477
+ )
478
+ all_knowledge.extend(layers["project"].knowledge_uuids)
479
+ all_resources.extend(layers["project"].resource_ids)
480
+ all_policies.extend(layers["project"].policy_ids)
481
+ except Exception as e:
482
+ logger.warning("failed_to_get_project_context", error=str(e), project_id=project_id)
483
+
484
+ # 5. Layer 4: Entity's own context
485
+ try:
486
+ entity_context = await _get_or_create_context(db, entity_type, entity_id, org_id)
487
+ layers[entity_type] = ContextData(
488
+ knowledge_uuids=entity_context.get("knowledge_uuids", []),
489
+ resource_ids=entity_context.get("resource_ids", []),
490
+ policy_ids=entity_context.get("policy_ids", []),
491
+ )
492
+ all_knowledge.extend(layers[entity_type].knowledge_uuids)
493
+ all_resources.extend(layers[entity_type].resource_ids)
494
+ all_policies.extend(layers[entity_type].policy_ids)
495
+ except Exception as e:
496
+ logger.warning("failed_to_get_entity_context", error=str(e), entity_type=entity_type, entity_id=entity_id)
497
+
498
+ # Deduplicate while preserving order
499
+ unique_knowledge = list(dict.fromkeys(all_knowledge))
500
+ unique_resources = list(dict.fromkeys(all_resources))
501
+ unique_policies = list(dict.fromkeys(all_policies))
502
+
503
+ logger.info(
504
+ "context_resolved",
505
+ entity_type=entity_type,
506
+ entity_id=entity_id,
507
+ layers_count=len(layers),
508
+ environment_count=len(environment_ids),
509
+ total_knowledge=len(unique_knowledge),
510
+ total_resources=len(unique_resources),
511
+ total_policies=len(unique_policies),
512
+ org_id=org_id,
513
+ )
514
+
515
+ return ResolvedContextResponse(
516
+ entity_id=entity_id,
517
+ entity_type=entity_type,
518
+ environment_id=environment_ids[0] if environment_ids else None,
519
+ team_id=team_id,
520
+ project_id=project_id,
521
+ knowledge_uuids=unique_knowledge,
522
+ resource_ids=unique_resources,
523
+ policy_ids=unique_policies,
524
+ layers=layers,
525
+ )
526
+
527
+ except HTTPException:
528
+ raise
529
+ except Exception as e:
530
+ logger.error("resolve_context_failed", error=str(e), entity_type=entity_type, entity_id=entity_id)
531
+ raise HTTPException(
532
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
533
+ detail=f"Failed to resolve {entity_type} context: {str(e)}"
534
+ )
535
+
536
+
537
+ # Convenience endpoints for workers
538
+ @router.get("/agents/{agent_id}/context/resolved", response_model=ResolvedContextResponse)
539
+ async def resolve_agent_context(
540
+ agent_id: str,
541
+ request: Request,
542
+ organization: dict = Depends(get_current_organization),
543
+ db: Session = Depends(get_db),
544
+ ):
545
+ """
546
+ Convenience endpoint to resolve full context for an agent.
547
+
548
+ Fetches and merges context from:
549
+ 1. ALL agent environments (many-to-many)
550
+ 2. Team (if agent belongs to a team)
551
+ 3. ALL team environments
552
+ 4. Project (if assigned)
553
+ 5. Agent's own context
554
+
555
+ Workers should call this endpoint to get all knowledge, resources, and policies.
556
+ """
557
+ return await resolve_context("agent", agent_id, request, organization, db)
558
+
559
+
560
+ @router.get("/teams/{team_id}/context/resolved", response_model=ResolvedContextResponse)
561
+ async def resolve_team_context(
562
+ team_id: str,
563
+ request: Request,
564
+ organization: dict = Depends(get_current_organization),
565
+ db: Session = Depends(get_db),
566
+ ):
567
+ """
568
+ Convenience endpoint to resolve full context for a team.
569
+
570
+ Fetches and merges context from:
571
+ 1. ALL team environments (many-to-many)
572
+ 2. Project (if assigned)
573
+ 3. Team's own context
574
+
575
+ Workers should call this endpoint to get all knowledge, resources, and policies.
576
+ """
577
+ return await resolve_context("team", team_id, request, organization, db)