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,59 @@
1
+ """Authentication validation endpoints for delegated auth from other services."""
2
+
3
+ from fastapi import APIRouter, Depends
4
+ from typing import Dict
5
+ import structlog
6
+
7
+ from control_plane_api.app.middleware.auth import get_current_organization
8
+
9
+ logger = structlog.get_logger()
10
+
11
+ router = APIRouter(prefix="/api/v1/auth", tags=["authentication"])
12
+
13
+
14
+ @router.get("/validate")
15
+ async def validate_token(
16
+ organization: dict = Depends(get_current_organization)
17
+ ) -> Dict:
18
+ """
19
+ Validate authentication token and return organization data.
20
+
21
+ This endpoint allows other services (like context-graph-api) to validate
22
+ tokens without duplicating auth logic. The control plane handles all
23
+ validation, caching, and Kubiya API integration.
24
+
25
+ The token should be passed in the Authorization header:
26
+ - Bearer <token> for user JWT tokens
27
+ - UserKey <token> for worker/API key tokens
28
+
29
+ Returns:
30
+ Organization dict with user and org information:
31
+ {
32
+ "id": "org-slug",
33
+ "name": "Organization Name",
34
+ "slug": "org-slug",
35
+ "user_id": "user-uuid",
36
+ "user_email": "user@example.com",
37
+ "user_name": "User Name",
38
+ "user_avatar": "...",
39
+ "user_status": "...",
40
+ "user_groups": [...]
41
+ }
42
+
43
+ Raises:
44
+ 401: Invalid or expired token
45
+ 500: Internal server error
46
+
47
+ Example:
48
+ ```bash
49
+ curl -H "Authorization: Bearer <token>" \\
50
+ https://control-plane.kubiya.ai/api/v1/auth/validate
51
+ ```
52
+ """
53
+ logger.info(
54
+ "auth_validation_delegated",
55
+ org_slug=organization["slug"],
56
+ user_id=organization.get("user_id"),
57
+ )
58
+
59
+ return organization
@@ -0,0 +1,57 @@
1
+ """
2
+ Client Configuration Router
3
+
4
+ Provides configuration endpoints for CLI and other clients to discover
5
+ backend service URLs and credentials.
6
+ """
7
+
8
+ from fastapi import APIRouter, Depends
9
+ from pydantic import BaseModel
10
+ from typing import Optional
11
+
12
+ from control_plane_api.app.middleware.auth import get_current_organization
13
+ from control_plane_api.app.config import get_api_config
14
+
15
+ settings = get_api_config()
16
+
17
+ router = APIRouter(prefix="/client", tags=["client-config"])
18
+
19
+
20
+ class ClientConfig(BaseModel):
21
+ """Configuration for CLI clients."""
22
+
23
+ # Backend service URLs
24
+ context_graph_api_base: str
25
+
26
+ # Future: LLM credentials (for direct client-side agent execution)
27
+ # litellm_api_base: Optional[str] = None
28
+ # litellm_api_key: Optional[str] = None
29
+
30
+ # Future: Temporal configuration
31
+ # temporal_address: Optional[str] = None
32
+ # temporal_namespace: Optional[str] = None
33
+
34
+ # Organization context
35
+ organization_id: str
36
+ organization_name: str
37
+
38
+
39
+ @router.get("/config", response_model=ClientConfig)
40
+ async def get_client_config(
41
+ organization: dict = Depends(get_current_organization),
42
+ ):
43
+ """
44
+ Get client configuration including backend service URLs.
45
+
46
+ This endpoint allows CLI clients to discover the context graph API URL
47
+ and other service endpoints, enabling direct connections without proxying
48
+ through the control plane.
49
+
50
+ Returns:
51
+ ClientConfig with service URLs and credentials
52
+ """
53
+ return ClientConfig(
54
+ context_graph_api_base=settings.context_graph_api_base,
55
+ organization_id=organization["id"],
56
+ organization_name=organization.get("name", organization["id"]),
57
+ )
@@ -0,0 +1,561 @@
1
+ """
2
+ Context Graph Router - Proxy to Context Graph API
3
+
4
+ This router provides access to the Context Graph API (Neo4j-based context graphs)
5
+ with org and integration namespaces. All endpoints are proxied with authentication.
6
+ """
7
+
8
+ import httpx
9
+ from fastapi import APIRouter, Depends, HTTPException, Request, Response
10
+ from typing import Optional, Dict, Any
11
+ import structlog
12
+
13
+ from control_plane_api.app.middleware.auth import get_current_organization
14
+ from control_plane_api.app.config import settings
15
+
16
+ logger = structlog.get_logger()
17
+
18
+ router = APIRouter(prefix="/context-graph", tags=["context-graph"])
19
+
20
+
21
+ async def proxy_graph_request(
22
+ request: Request,
23
+ path: str,
24
+ method: str = "GET",
25
+ query_params: Optional[Dict[str, Any]] = None,
26
+ body: Optional[Dict[str, Any]] = None,
27
+ organization: dict = None,
28
+ ) -> Response:
29
+ """
30
+ Generic proxy function for Context Graph API requests.
31
+
32
+ Args:
33
+ request: FastAPI request object
34
+ path: Path to proxy (e.g., "/api/v1/graph/nodes")
35
+ method: HTTP method
36
+ query_params: Query parameters
37
+ body: Request body (for POST requests)
38
+ organization: Organization context
39
+
40
+ Returns:
41
+ FastAPI Response with proxied content
42
+ """
43
+ try:
44
+ token = request.state.kubiya_token
45
+ auth_type = getattr(request.state, "kubiya_auth_type", "Bearer")
46
+ org_id = organization["id"] if organization else None
47
+
48
+ # Prepare headers for Context Graph API
49
+ headers = {
50
+ "Authorization": f"{auth_type} {token}",
51
+ "Accept": "application/json",
52
+ "Content-Type": "application/json",
53
+ "X-Kubiya-Client": "agent-control-plane",
54
+ }
55
+
56
+ if org_id:
57
+ headers["X-Organization-ID"] = org_id
58
+
59
+ # Forward Accept-Encoding header to disable gzip if requested by client
60
+ if "accept-encoding" in request.headers:
61
+ headers["Accept-Encoding"] = request.headers["accept-encoding"]
62
+
63
+ # Build full URL
64
+ base_url = settings.context_graph_api_base.rstrip("/")
65
+ full_url = f"{base_url}{path}"
66
+
67
+ # Make request to Context Graph API
68
+ async with httpx.AsyncClient(timeout=settings.context_graph_api_timeout) as client:
69
+ if method == "GET":
70
+ response = await client.get(full_url, headers=headers, params=query_params)
71
+ elif method == "POST":
72
+ response = await client.post(full_url, headers=headers, params=query_params, json=body)
73
+ elif method == "PUT":
74
+ response = await client.put(full_url, headers=headers, params=query_params, json=body)
75
+ elif method == "DELETE":
76
+ response = await client.delete(full_url, headers=headers, params=query_params)
77
+ else:
78
+ raise HTTPException(status_code=405, detail=f"Method {method} not allowed")
79
+
80
+ logger.info(
81
+ "context_graph_request",
82
+ org_id=org_id,
83
+ path=path,
84
+ method=method,
85
+ status=response.status_code,
86
+ )
87
+
88
+ # Clean response headers - remove compression headers since we handle encoding
89
+ response_headers = dict(response.headers)
90
+ # Remove headers that might cause decompression issues
91
+ response_headers.pop("content-encoding", None)
92
+ response_headers.pop("content-length", None) # Will be recalculated
93
+
94
+ # Return response with original status code
95
+ return Response(
96
+ content=response.content,
97
+ status_code=response.status_code,
98
+ headers=response_headers,
99
+ media_type=response.headers.get("content-type", "application/json"),
100
+ )
101
+
102
+ except httpx.TimeoutException:
103
+ logger.error("context_graph_timeout", path=path, method=method)
104
+ raise HTTPException(status_code=504, detail="Context Graph API request timed out")
105
+ except httpx.RequestError as e:
106
+ logger.error("context_graph_request_error", error=str(e), path=path)
107
+ raise HTTPException(status_code=502, detail=f"Failed to connect to Context Graph API: {str(e)}")
108
+ except HTTPException:
109
+ raise
110
+ except Exception as e:
111
+ logger.error("context_graph_unexpected_error", error=str(e), error_type=type(e).__name__)
112
+ raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
113
+
114
+
115
+ @router.get("/health")
116
+ async def health_check(
117
+ request: Request,
118
+ organization: dict = Depends(get_current_organization),
119
+ ):
120
+ """Health check endpoint for Context Graph API."""
121
+ return await proxy_graph_request(
122
+ request=request,
123
+ path="/health",
124
+ method="GET",
125
+ organization=organization,
126
+ )
127
+
128
+
129
+ @router.post("/api/v1/graph/nodes/search")
130
+ async def search_nodes(
131
+ request: Request,
132
+ body: Dict[str, Any],
133
+ integration: Optional[str] = None,
134
+ skip: int = 0,
135
+ limit: int = 100,
136
+ organization: dict = Depends(get_current_organization),
137
+ ):
138
+ """
139
+ Search for nodes in the context graph.
140
+
141
+ Body should contain NodeSearchRequest:
142
+ - label: Optional node label to filter by
143
+ - property_name: Optional property name to filter by
144
+ - property_value: Optional property value to match
145
+ """
146
+ query_params = {"skip": skip, "limit": limit}
147
+ if integration:
148
+ query_params["integration"] = integration
149
+
150
+ return await proxy_graph_request(
151
+ request=request,
152
+ path="/api/v1/graph/nodes/search",
153
+ method="POST",
154
+ query_params=query_params,
155
+ body=body,
156
+ organization=organization,
157
+ )
158
+
159
+
160
+ @router.get("/api/v1/graph/nodes/{node_id}")
161
+ async def get_node(
162
+ node_id: str,
163
+ request: Request,
164
+ integration: Optional[str] = None,
165
+ organization: dict = Depends(get_current_organization),
166
+ ):
167
+ """Get a specific node by its ID."""
168
+ query_params = {}
169
+ if integration:
170
+ query_params["integration"] = integration
171
+
172
+ return await proxy_graph_request(
173
+ request=request,
174
+ path=f"/api/v1/graph/nodes/{node_id}",
175
+ method="GET",
176
+ query_params=query_params,
177
+ organization=organization,
178
+ )
179
+
180
+
181
+ @router.get("/api/v1/graph/nodes/{node_id}/relationships")
182
+ async def get_relationships(
183
+ node_id: str,
184
+ request: Request,
185
+ direction: str = "both",
186
+ relationship_type: Optional[str] = None,
187
+ integration: Optional[str] = None,
188
+ skip: int = 0,
189
+ limit: int = 100,
190
+ organization: dict = Depends(get_current_organization),
191
+ ):
192
+ """Get relationships for a specific node."""
193
+ query_params = {
194
+ "direction": direction,
195
+ "skip": skip,
196
+ "limit": limit,
197
+ }
198
+ if relationship_type:
199
+ query_params["relationship_type"] = relationship_type
200
+ if integration:
201
+ query_params["integration"] = integration
202
+
203
+ return await proxy_graph_request(
204
+ request=request,
205
+ path=f"/api/v1/graph/nodes/{node_id}/relationships",
206
+ method="GET",
207
+ query_params=query_params,
208
+ organization=organization,
209
+ )
210
+
211
+
212
+ @router.post("/api/v1/graph/subgraph")
213
+ async def get_subgraph(
214
+ request: Request,
215
+ body: Dict[str, Any],
216
+ integration: Optional[str] = None,
217
+ organization: dict = Depends(get_current_organization),
218
+ ):
219
+ """
220
+ Get a subgraph starting from a node.
221
+
222
+ Body should contain SubgraphRequest:
223
+ - node_id: Starting node ID
224
+ - depth: Traversal depth (1-5)
225
+ - relationship_types: Optional list of relationship types to follow
226
+ """
227
+ query_params = {}
228
+ if integration:
229
+ query_params["integration"] = integration
230
+
231
+ return await proxy_graph_request(
232
+ request=request,
233
+ path="/api/v1/graph/subgraph",
234
+ method="POST",
235
+ query_params=query_params,
236
+ body=body,
237
+ organization=organization,
238
+ )
239
+
240
+
241
+ @router.post("/api/v1/graph/nodes/search/text")
242
+ async def search_by_text(
243
+ request: Request,
244
+ body: Dict[str, Any],
245
+ integration: Optional[str] = None,
246
+ skip: int = 0,
247
+ limit: int = 100,
248
+ organization: dict = Depends(get_current_organization),
249
+ ):
250
+ """
251
+ Search nodes by text pattern in a property.
252
+
253
+ Body should contain TextSearchRequest:
254
+ - property_name: Property name to search in
255
+ - search_text: Text to search for
256
+ - label: Optional node label to filter by
257
+ """
258
+ query_params = {"skip": skip, "limit": limit}
259
+ if integration:
260
+ query_params["integration"] = integration
261
+
262
+ return await proxy_graph_request(
263
+ request=request,
264
+ path="/api/v1/graph/nodes/search/text",
265
+ method="POST",
266
+ query_params=query_params,
267
+ body=body,
268
+ organization=organization,
269
+ )
270
+
271
+
272
+ @router.get("/api/v1/graph/nodes")
273
+ async def get_all_nodes(
274
+ request: Request,
275
+ integration: Optional[str] = None,
276
+ skip: int = 0,
277
+ limit: int = 100,
278
+ organization: dict = Depends(get_current_organization),
279
+ ):
280
+ """
281
+ Get all nodes in the organization.
282
+
283
+ Optionally filter by integration label to get nodes from a specific integration.
284
+ """
285
+ query_params = {"skip": skip, "limit": limit}
286
+ if integration:
287
+ query_params["integration"] = integration
288
+
289
+ return await proxy_graph_request(
290
+ request=request,
291
+ path="/api/v1/graph/nodes",
292
+ method="GET",
293
+ query_params=query_params,
294
+ organization=organization,
295
+ )
296
+
297
+
298
+ @router.get("/api/v1/graph/labels")
299
+ async def get_labels(
300
+ request: Request,
301
+ integration: Optional[str] = None,
302
+ skip: int = 0,
303
+ limit: int = 100,
304
+ organization: dict = Depends(get_current_organization),
305
+ ):
306
+ """Get all node labels in the context graph."""
307
+ query_params = {"skip": skip, "limit": limit}
308
+ if integration:
309
+ query_params["integration"] = integration
310
+
311
+ return await proxy_graph_request(
312
+ request=request,
313
+ path="/api/v1/graph/labels",
314
+ method="GET",
315
+ query_params=query_params,
316
+ organization=organization,
317
+ )
318
+
319
+
320
+ @router.get("/api/v1/graph/relationship-types")
321
+ async def get_relationship_types(
322
+ request: Request,
323
+ integration: Optional[str] = None,
324
+ skip: int = 0,
325
+ limit: int = 100,
326
+ organization: dict = Depends(get_current_organization),
327
+ ):
328
+ """Get all relationship types in the context graph."""
329
+ query_params = {"skip": skip, "limit": limit}
330
+ if integration:
331
+ query_params["integration"] = integration
332
+
333
+ return await proxy_graph_request(
334
+ request=request,
335
+ path="/api/v1/graph/relationship-types",
336
+ method="GET",
337
+ query_params=query_params,
338
+ organization=organization,
339
+ )
340
+
341
+
342
+ @router.get("/api/v1/graph/stats")
343
+ async def get_stats(
344
+ request: Request,
345
+ integration: Optional[str] = None,
346
+ skip: int = 0,
347
+ limit: int = 100,
348
+ organization: dict = Depends(get_current_organization),
349
+ ):
350
+ """Get statistics about the context graph."""
351
+ query_params = {"skip": skip, "limit": limit}
352
+ if integration:
353
+ query_params["integration"] = integration
354
+
355
+ return await proxy_graph_request(
356
+ request=request,
357
+ path="/api/v1/graph/stats",
358
+ method="GET",
359
+ query_params=query_params,
360
+ organization=organization,
361
+ )
362
+
363
+
364
+ @router.post("/api/v1/graph/query")
365
+ async def execute_query(
366
+ request: Request,
367
+ body: Dict[str, Any],
368
+ organization: dict = Depends(get_current_organization),
369
+ ):
370
+ """
371
+ Execute a custom Cypher query (read-only).
372
+
373
+ The query will be automatically scoped to your organization's data.
374
+ All node patterns will have the organization label injected.
375
+
376
+ Body should contain CustomQueryRequest:
377
+ - query: Cypher query to execute (read-only)
378
+ """
379
+ return await proxy_graph_request(
380
+ request=request,
381
+ path="/api/v1/graph/query",
382
+ method="POST",
383
+ body=body,
384
+ organization=organization,
385
+ )
386
+
387
+
388
+ @router.get("/api/v1/graph/integrations")
389
+ async def get_integrations(
390
+ request: Request,
391
+ skip: int = 0,
392
+ limit: int = 100,
393
+ organization: dict = Depends(get_current_organization),
394
+ ):
395
+ """Get all available integrations for the organization."""
396
+ query_params = {"skip": skip, "limit": limit}
397
+
398
+ return await proxy_graph_request(
399
+ request=request,
400
+ path="/api/v1/graph/integrations",
401
+ method="GET",
402
+ query_params=query_params,
403
+ organization=organization,
404
+ )
405
+
406
+
407
+ # ============================================================================
408
+ # Semantic Search Endpoint
409
+ # ============================================================================
410
+
411
+
412
+ @router.post("/graph/search")
413
+ async def semantic_search(
414
+ request: Request,
415
+ body: Dict[str, Any],
416
+ organization: dict = Depends(get_current_organization),
417
+ ):
418
+ """
419
+ Semantic search across knowledge graph.
420
+
421
+ Performs vector similarity search over processed knowledge to find
422
+ relevant information based on natural language queries.
423
+
424
+ Body should contain:
425
+ - query: Natural language question or keywords (required)
426
+ - limit: Maximum results (1-100, default 10)
427
+ - filters: Optional filters (dataset_ids, etc.)
428
+ - search_type: Search strategy (GRAPH_COMPLETION, CHUNKS, RAG_COMPLETION, TEMPORAL, FEEDBACK)
429
+ """
430
+ return await proxy_graph_request(
431
+ request=request,
432
+ path="/api/v1/graph/search",
433
+ method="POST",
434
+ body=body,
435
+ organization=organization,
436
+ )
437
+
438
+
439
+ # ============================================================================
440
+ # Intelligent Search Endpoints
441
+ # ============================================================================
442
+
443
+
444
+ @router.post("/intelligent-search")
445
+ async def intelligent_search(
446
+ request: Request,
447
+ body: Dict[str, Any],
448
+ organization: dict = Depends(get_current_organization),
449
+ ):
450
+ """
451
+ Perform AI-powered intelligent graph search using natural language.
452
+
453
+ Body should contain IntelligentSearchRequest:
454
+ - keywords: Natural language query (required)
455
+ - max_turns: Maximum agent turns (1-20, default: 5)
456
+ - system_prompt: Optional system prompt
457
+ - additional_context: Optional additional context
458
+ - model: LiteLLM model name (default: kubiya/claude-sonnet-4)
459
+ - temperature: Model temperature (0.0-2.0, default: 0.7)
460
+ - integration: Filter by integration
461
+ - label_filter: Filter by node label
462
+ - enable_semantic_search: Enable semantic search
463
+ - enable_cypher_queries: Enable custom Cypher queries
464
+ - strategy: Agent strategy (claude_sdk or agno)
465
+ - session_id: Session ID for multi-turn conversations
466
+ """
467
+ return await proxy_graph_request(
468
+ request=request,
469
+ path="/api/v1/graph/intelligent-search",
470
+ method="POST",
471
+ body=body,
472
+ organization=organization,
473
+ )
474
+
475
+
476
+ @router.post("/intelligent-search/stream")
477
+ async def intelligent_search_stream(
478
+ request: Request,
479
+ body: Dict[str, Any],
480
+ organization: dict = Depends(get_current_organization),
481
+ ):
482
+ """
483
+ Perform streaming AI-powered intelligent graph search with real-time updates.
484
+
485
+ Returns Server-Sent Events (SSE) stream with:
486
+ - session: Session ID
487
+ - progress: Progress updates with percentage
488
+ - tool_call: Tool invocations
489
+ - partial_answer: Incremental answer text
490
+ - complete: Final results
491
+ - error: Error messages
492
+ """
493
+ # For streaming, we need to handle SSE differently
494
+ # Use the proxy but preserve streaming response
495
+ try:
496
+ token = request.state.kubiya_token
497
+ auth_type = getattr(request.state, "kubiya_auth_type", "Bearer")
498
+ org_id = organization["id"] if organization else None
499
+
500
+ headers = {
501
+ "Authorization": f"{auth_type} {token}",
502
+ "Accept": "text/event-stream",
503
+ "Content-Type": "application/json",
504
+ "X-Kubiya-Client": "agent-control-plane",
505
+ }
506
+
507
+ if org_id:
508
+ headers["X-Organization-ID"] = org_id
509
+
510
+ base_url = settings.context_graph_api_base.rstrip("/")
511
+ full_url = f"{base_url}/api/v1/graph/intelligent-search/stream"
512
+
513
+ async with httpx.AsyncClient(timeout=settings.context_graph_api_timeout) as client:
514
+ response = await client.post(full_url, headers=headers, json=body)
515
+
516
+ logger.info(
517
+ "context_graph_streaming_request",
518
+ org_id=org_id,
519
+ path="/api/v1/graph/intelligent-search/stream",
520
+ status=response.status_code,
521
+ )
522
+
523
+ # Return streaming response
524
+ return Response(
525
+ content=response.content,
526
+ status_code=response.status_code,
527
+ headers=dict(response.headers),
528
+ media_type="text/event-stream",
529
+ )
530
+
531
+ except httpx.TimeoutException:
532
+ logger.error("context_graph_stream_timeout")
533
+ raise HTTPException(status_code=504, detail="Streaming search timed out")
534
+ except httpx.RequestError as e:
535
+ logger.error("context_graph_stream_error", error=str(e))
536
+ raise HTTPException(status_code=502, detail=f"Failed to connect: {str(e)}")
537
+ except Exception as e:
538
+ logger.error("context_graph_stream_unexpected_error", error=str(e))
539
+ raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
540
+
541
+
542
+ @router.get("/intelligent-search/health")
543
+ async def intelligent_search_health(
544
+ request: Request,
545
+ organization: dict = Depends(get_current_organization),
546
+ ):
547
+ """
548
+ Check health status of intelligent search service.
549
+
550
+ Returns:
551
+ - status: "healthy", "degraded", or "unhealthy"
552
+ - strategies: Available agent strategies
553
+ - configuration: Service configuration
554
+ - message: Status message
555
+ """
556
+ return await proxy_graph_request(
557
+ request=request,
558
+ path="/api/v1/graph/intelligent-search/health",
559
+ method="GET",
560
+ organization=organization,
561
+ )