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,140 @@
1
+ """
2
+ Skill Definitions Router
3
+
4
+ Provides endpoints to query available skill types, variants, and templates
5
+ from the skill registry.
6
+ """
7
+ from fastapi import APIRouter
8
+ from typing import List, Dict, Any
9
+ import structlog
10
+
11
+ from control_plane_api.app.skills import get_all_skills, get_skill, SkillType
12
+
13
+ logger = structlog.get_logger()
14
+
15
+ router = APIRouter()
16
+
17
+
18
+ @router.get("/definitions")
19
+ async def list_skill_definitions():
20
+ """
21
+ Get all available skill definitions with their variants.
22
+
23
+ This returns the registry of all skill types that can be instantiated,
24
+ along with their predefined variants/presets.
25
+ """
26
+ skills = get_all_skills()
27
+
28
+ result = []
29
+ for skill in skills:
30
+ result.append(skill.to_dict())
31
+
32
+ logger.info(f"Returning {len(result)} skill definitions")
33
+ return {"skills": result}
34
+
35
+
36
+ @router.get("/definitions/{skill_type}")
37
+ async def get_skill_definition(skill_type: str):
38
+ """
39
+ Get a specific skill definition by type.
40
+
41
+ Returns detailed information about a skill type including all variants.
42
+ """
43
+ try:
44
+ ts_type = SkillType(skill_type)
45
+ except ValueError:
46
+ from fastapi import HTTPException
47
+ raise HTTPException(status_code=404, detail=f"Skill type '{skill_type}' not found")
48
+
49
+ skill = get_skill(ts_type)
50
+ if not skill:
51
+ from fastapi import HTTPException
52
+ raise HTTPException(status_code=404, detail=f"Skill type '{skill_type}' not registered")
53
+
54
+ return skill.to_dict()
55
+
56
+
57
+ @router.get("/definitions/{skill_type}/variants")
58
+ async def list_skill_variants(skill_type: str):
59
+ """
60
+ Get all variants/presets for a specific skill type.
61
+
62
+ Variants are predefined configurations (e.g., "Read Only", "Full Access")
63
+ that users can quickly apply.
64
+ """
65
+ try:
66
+ ts_type = SkillType(skill_type)
67
+ except ValueError:
68
+ from fastapi import HTTPException
69
+ raise HTTPException(status_code=404, detail=f"Skill type '{skill_type}' not found")
70
+
71
+ skill = get_skill(ts_type)
72
+ if not skill:
73
+ from fastapi import HTTPException
74
+ raise HTTPException(status_code=404, detail=f"Skill type '{skill_type}' not registered")
75
+
76
+ variants = skill.get_variants()
77
+ return {
78
+ "type": skill.type.value,
79
+ "name": skill.name,
80
+ "variants": [v.model_dump() for v in variants]
81
+ }
82
+
83
+
84
+ @router.get("/templates")
85
+ async def list_skill_templates():
86
+ """
87
+ Get all predefined skill templates (flattened variants).
88
+
89
+ This is a convenience endpoint that returns all variants from all skills
90
+ as a flat list of ready-to-use templates.
91
+ """
92
+ skills = get_all_skills()
93
+
94
+ templates = []
95
+ for skill in skills:
96
+ for variant in skill.get_variants():
97
+ templates.append({
98
+ "id": variant.id,
99
+ "name": variant.name,
100
+ "type": skill.type.value,
101
+ "description": variant.description,
102
+ "icon": variant.icon or skill.icon,
103
+ "icon_type": skill.icon_type,
104
+ "category": variant.category.value,
105
+ "badge": variant.badge,
106
+ "configuration": variant.configuration,
107
+ "is_default": variant.is_default,
108
+ })
109
+
110
+ logger.info(f"Returning {len(templates)} skill templates")
111
+ return {"templates": templates}
112
+
113
+
114
+ @router.post("/definitions/{skill_type}/validate")
115
+ async def validate_skill_configuration(skill_type: str, configuration: Dict[str, Any]):
116
+ """
117
+ Validate a configuration for a specific skill type.
118
+
119
+ Returns the validated and normalized configuration.
120
+ """
121
+ try:
122
+ ts_type = SkillType(skill_type)
123
+ except ValueError:
124
+ from fastapi import HTTPException
125
+ raise HTTPException(status_code=400, detail=f"Invalid skill type: {skill_type}")
126
+
127
+ skill = get_skill(ts_type)
128
+ if not skill:
129
+ from fastapi import HTTPException
130
+ raise HTTPException(status_code=404, detail=f"Skill type '{skill_type}' not registered")
131
+
132
+ try:
133
+ validated_config = skill.validate_configuration(configuration)
134
+ return {
135
+ "valid": True,
136
+ "configuration": validated_config
137
+ }
138
+ except Exception as e:
139
+ from fastapi import HTTPException
140
+ raise HTTPException(status_code=400, detail=f"Invalid configuration: {str(e)}")
@@ -0,0 +1,456 @@
1
+ """
2
+ Storage Router - Remote Filesystem API
3
+
4
+ Provides RESTful endpoints for cloud file storage operations:
5
+ - File CRUD (upload, download, delete, list)
6
+ - Advanced operations (move, copy, search)
7
+ - Folder management
8
+ - Batch operations
9
+ - Usage analytics
10
+ """
11
+
12
+ from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Query, Request
13
+ from fastapi.responses import StreamingResponse
14
+ from typing import List, Optional
15
+ from pydantic import BaseModel, Field
16
+ import structlog
17
+ from datetime import datetime
18
+ import zipfile
19
+ from io import BytesIO
20
+
21
+ from control_plane_api.app.middleware.auth import get_current_organization
22
+ from control_plane_api.app.services.storage_service import StorageService, StorageQuotaExceeded
23
+
24
+ logger = structlog.get_logger()
25
+ router = APIRouter()
26
+
27
+
28
+ # ============================================================================
29
+ # Pydantic Schemas
30
+ # ============================================================================
31
+
32
+ class FileMetadata(BaseModel):
33
+ """File metadata response"""
34
+ id: str
35
+ file_name: str
36
+ file_path: str
37
+ content_type: str
38
+ file_size_bytes: int
39
+ checksum: Optional[str]
40
+ tags: List[str] = Field(default_factory=list)
41
+ custom_metadata: dict = Field(default_factory=dict)
42
+ uploaded_by: str
43
+ created_at: str
44
+ updated_at: str
45
+ last_accessed_at: Optional[str]
46
+ access_count: int
47
+ provider: str
48
+
49
+
50
+ class BatchDownloadRequest(BaseModel):
51
+ """Batch download request"""
52
+ file_ids: List[str] = Field(..., min_length=1, max_length=100)
53
+ archive_name: str = Field(default="files.zip")
54
+
55
+
56
+ class SearchFilesRequest(BaseModel):
57
+ """File search request"""
58
+ query: Optional[str] = None
59
+ tags: Optional[List[str]] = None
60
+ path_prefix: Optional[str] = None
61
+ content_type: Optional[str] = None
62
+ min_size: Optional[int] = None
63
+ max_size: Optional[int] = None
64
+ uploaded_by: Optional[str] = None
65
+
66
+
67
+ class UsageStatsResponse(BaseModel):
68
+ """Storage usage statistics"""
69
+ organization_id: str
70
+ total_bytes_used: int
71
+ total_files_count: int
72
+ quota_bytes: int
73
+ remaining_bytes: int
74
+ usage_percentage: float
75
+ total_bytes_uploaded: int
76
+ total_bytes_downloaded: int
77
+
78
+
79
+ class MoveFileRequest(BaseModel):
80
+ """Move file request"""
81
+ new_path: str
82
+
83
+
84
+ class CopyFileRequest(BaseModel):
85
+ """Copy file request"""
86
+ destination_path: str
87
+
88
+
89
+ class UpdateMetadataRequest(BaseModel):
90
+ """Update file metadata request"""
91
+ tags: Optional[List[str]] = None
92
+ custom_metadata: Optional[dict] = None
93
+
94
+
95
+ # ============================================================================
96
+ # File Operations Endpoints
97
+ # ============================================================================
98
+
99
+ @router.post("/files/upload", status_code=status.HTTP_201_CREATED)
100
+ async def upload_file(
101
+ file: UploadFile = File(...),
102
+ file_path: str = Query(..., description="Destination path (e.g., /folder/file.txt)"),
103
+ tags: Optional[str] = Query(None, description="Comma-separated tags"),
104
+ organization: dict = Depends(get_current_organization),
105
+ ):
106
+ """
107
+ Upload a file to cloud storage.
108
+
109
+ - Enforces organization quota
110
+ - Supports custom metadata and tags
111
+ - Returns file metadata with provider URL
112
+ """
113
+ try:
114
+ storage_service = StorageService(organization["id"])
115
+
116
+ # Parse tags
117
+ tag_list = [t.strip() for t in tags.split(",")] if tags else []
118
+
119
+ # Upload file
120
+ file_metadata = await storage_service.upload_file(
121
+ file_content=file.file,
122
+ file_name=file.filename or "unnamed",
123
+ file_path=file_path,
124
+ content_type=file.content_type or "application/octet-stream",
125
+ uploaded_by=organization.get("user_id", "unknown"),
126
+ tags=tag_list,
127
+ custom_metadata={}
128
+ )
129
+
130
+ logger.info(
131
+ "file_uploaded",
132
+ organization_id=organization["id"],
133
+ file_name=file.filename,
134
+ file_size=file_metadata["file_size_bytes"],
135
+ file_id=file_metadata["id"]
136
+ )
137
+
138
+ return file_metadata
139
+
140
+ except StorageQuotaExceeded as e:
141
+ raise HTTPException(
142
+ status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
143
+ detail=str(e)
144
+ )
145
+ except Exception as e:
146
+ logger.error("file_upload_failed", error=str(e), organization_id=organization["id"])
147
+ raise HTTPException(
148
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
149
+ detail=f"Upload failed: {str(e)}"
150
+ )
151
+
152
+
153
+ @router.get("/files/{file_id}/download")
154
+ async def download_file(
155
+ file_id: str,
156
+ organization: dict = Depends(get_current_organization),
157
+ ):
158
+ """
159
+ Download a file from cloud storage.
160
+
161
+ - Streams file content
162
+ - Updates access tracking
163
+ - Returns proper content-type headers
164
+ """
165
+ try:
166
+ storage_service = StorageService(organization["id"])
167
+
168
+ # Get file metadata and stream
169
+ file_stream, file_metadata = await storage_service.download_file(file_id)
170
+
171
+ return StreamingResponse(
172
+ file_stream,
173
+ media_type=file_metadata["content_type"],
174
+ headers={
175
+ "Content-Disposition": f'attachment; filename="{file_metadata["file_name"]}"',
176
+ "Content-Length": str(file_metadata["file_size_bytes"]),
177
+ }
178
+ )
179
+
180
+ except FileNotFoundError:
181
+ raise HTTPException(status_code=404, detail="File not found")
182
+ except Exception as e:
183
+ logger.error("file_download_failed", error=str(e), file_id=file_id)
184
+ raise HTTPException(status_code=500, detail="Download failed")
185
+
186
+
187
+ @router.delete("/files/{file_id}")
188
+ async def delete_file(
189
+ file_id: str,
190
+ permanent: bool = Query(False, description="Permanently delete (vs soft delete)"),
191
+ organization: dict = Depends(get_current_organization),
192
+ ):
193
+ """
194
+ Delete a file.
195
+
196
+ - Supports soft delete (default) or permanent deletion
197
+ - Updates usage statistics
198
+ """
199
+ try:
200
+ storage_service = StorageService(organization["id"])
201
+
202
+ success = await storage_service.delete_file(file_id, permanent=permanent)
203
+
204
+ if success:
205
+ logger.info(
206
+ "file_deleted",
207
+ organization_id=organization["id"],
208
+ file_id=file_id,
209
+ permanent=permanent
210
+ )
211
+ return {"success": True, "file_id": file_id, "permanent": permanent}
212
+ else:
213
+ raise HTTPException(status_code=404, detail="File not found")
214
+
215
+ except FileNotFoundError:
216
+ raise HTTPException(status_code=404, detail="File not found")
217
+ except Exception as e:
218
+ logger.error("file_delete_failed", error=str(e), file_id=file_id)
219
+ raise HTTPException(status_code=500, detail="Delete failed")
220
+
221
+
222
+ @router.get("/files", response_model=List[FileMetadata])
223
+ async def list_files(
224
+ path_prefix: Optional[str] = Query(None, description="Filter by path prefix"),
225
+ limit: int = Query(100, ge=1, le=1000, description="Maximum files to return"),
226
+ offset: int = Query(0, ge=0, description="Pagination offset"),
227
+ sort_by: str = Query("created_at", regex="^(created_at|file_name|file_size_bytes)$"),
228
+ sort_order: str = Query("desc", regex="^(asc|desc)$"),
229
+ organization: dict = Depends(get_current_organization),
230
+ ):
231
+ """
232
+ List files in organization's storage.
233
+
234
+ - Supports path filtering
235
+ - Pagination with limit/offset
236
+ - Sorting options
237
+ """
238
+ try:
239
+ storage_service = StorageService(organization["id"])
240
+ files = await storage_service.list_files(
241
+ path_prefix=path_prefix,
242
+ limit=limit,
243
+ offset=offset,
244
+ sort_by=sort_by,
245
+ sort_order=sort_order
246
+ )
247
+
248
+ logger.info(
249
+ "files_listed",
250
+ organization_id=organization["id"],
251
+ count=len(files),
252
+ path_prefix=path_prefix
253
+ )
254
+
255
+ return files
256
+
257
+ except Exception as e:
258
+ logger.error("list_files_failed", error=str(e))
259
+ raise HTTPException(status_code=500, detail="List failed")
260
+
261
+
262
+ @router.post("/files/search", response_model=List[FileMetadata])
263
+ async def search_files(
264
+ search_request: SearchFilesRequest,
265
+ organization: dict = Depends(get_current_organization),
266
+ ):
267
+ """
268
+ Advanced file search with multiple filters.
269
+
270
+ - Search by name, tags, metadata
271
+ - Filter by size, type, uploader
272
+ - Path prefix filtering
273
+ """
274
+ try:
275
+ storage_service = StorageService(organization["id"])
276
+ results = await storage_service.search_files(
277
+ query=search_request.query,
278
+ tags=search_request.tags,
279
+ path_prefix=search_request.path_prefix,
280
+ content_type=search_request.content_type,
281
+ min_size=search_request.min_size,
282
+ max_size=search_request.max_size,
283
+ uploaded_by=search_request.uploaded_by
284
+ )
285
+
286
+ logger.info(
287
+ "files_searched",
288
+ organization_id=organization["id"],
289
+ results_count=len(results),
290
+ query=search_request.query
291
+ )
292
+
293
+ return results
294
+
295
+ except Exception as e:
296
+ logger.error("search_files_failed", error=str(e))
297
+ raise HTTPException(status_code=500, detail="Search failed")
298
+
299
+
300
+ @router.post("/files/batch-download")
301
+ async def batch_download_files(
302
+ request: BatchDownloadRequest,
303
+ organization: dict = Depends(get_current_organization),
304
+ ):
305
+ """
306
+ Download multiple files as a ZIP archive.
307
+
308
+ - Maximum 100 files per request
309
+ - Streams ZIP archive
310
+ """
311
+ try:
312
+ storage_service = StorageService(organization["id"])
313
+
314
+ # Create ZIP archive in memory
315
+ zip_buffer = BytesIO()
316
+ with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
317
+ for file_id in request.file_ids:
318
+ try:
319
+ file_stream, file_metadata = await storage_service.download_file(file_id)
320
+
321
+ zip_file.writestr(
322
+ file_metadata["file_path"],
323
+ file_stream.read()
324
+ )
325
+ except Exception as e:
326
+ logger.warning("batch_download_file_skipped", file_id=file_id, error=str(e))
327
+ continue
328
+
329
+ zip_buffer.seek(0)
330
+
331
+ logger.info(
332
+ "batch_download_completed",
333
+ organization_id=organization["id"],
334
+ file_count=len(request.file_ids)
335
+ )
336
+
337
+ return StreamingResponse(
338
+ zip_buffer,
339
+ media_type="application/zip",
340
+ headers={
341
+ "Content-Disposition": f'attachment; filename="{request.archive_name}"'
342
+ }
343
+ )
344
+
345
+ except Exception as e:
346
+ logger.error("batch_download_failed", error=str(e))
347
+ raise HTTPException(status_code=500, detail="Batch download failed")
348
+
349
+
350
+ # ============================================================================
351
+ # Advanced Operations
352
+ # ============================================================================
353
+
354
+ @router.post("/files/{file_id}/move")
355
+ async def move_file(
356
+ file_id: str,
357
+ move_request: MoveFileRequest,
358
+ organization: dict = Depends(get_current_organization),
359
+ ):
360
+ """Move/rename a file."""
361
+ # TODO: Implement move operation
362
+ raise HTTPException(status_code=501, detail="Move operation not yet implemented")
363
+
364
+
365
+ @router.post("/files/{file_id}/copy")
366
+ async def copy_file(
367
+ file_id: str,
368
+ copy_request: CopyFileRequest,
369
+ organization: dict = Depends(get_current_organization),
370
+ ):
371
+ """Copy a file to a new location."""
372
+ # TODO: Implement copy operation
373
+ raise HTTPException(status_code=501, detail="Copy operation not yet implemented")
374
+
375
+
376
+ @router.get("/files/{file_id}/metadata", response_model=FileMetadata)
377
+ async def get_file_metadata(
378
+ file_id: str,
379
+ organization: dict = Depends(get_current_organization),
380
+ ):
381
+ """Get detailed file metadata."""
382
+ try:
383
+ storage_service = StorageService(organization["id"])
384
+ metadata = await storage_service.get_file_metadata(file_id)
385
+ return metadata
386
+
387
+ except FileNotFoundError:
388
+ raise HTTPException(status_code=404, detail="File not found")
389
+ except Exception as e:
390
+ logger.error("get_metadata_failed", error=str(e), file_id=file_id)
391
+ raise HTTPException(status_code=500, detail="Failed to get metadata")
392
+
393
+
394
+ @router.put("/files/{file_id}/metadata")
395
+ async def update_file_metadata(
396
+ file_id: str,
397
+ update_request: UpdateMetadataRequest,
398
+ organization: dict = Depends(get_current_organization),
399
+ ):
400
+ """Update file tags and custom metadata."""
401
+ # TODO: Implement metadata update
402
+ raise HTTPException(status_code=501, detail="Metadata update not yet implemented")
403
+
404
+
405
+ @router.post("/folders")
406
+ async def create_folder(
407
+ folder_path: str = Query(..., description="Folder path to create"),
408
+ organization: dict = Depends(get_current_organization),
409
+ ):
410
+ """Create a folder (explicit folder management)."""
411
+ # TODO: Implement folder creation
412
+ raise HTTPException(status_code=501, detail="Folder creation not yet implemented")
413
+
414
+
415
+ # ============================================================================
416
+ # Usage & Analytics
417
+ # ============================================================================
418
+
419
+ @router.get("/usage", response_model=UsageStatsResponse)
420
+ async def get_storage_usage(
421
+ organization: dict = Depends(get_current_organization),
422
+ ):
423
+ """Get current storage usage and quota information."""
424
+ try:
425
+ storage_service = StorageService(organization["id"])
426
+ usage = await storage_service.get_usage_stats()
427
+
428
+ logger.info(
429
+ "usage_stats_retrieved",
430
+ organization_id=organization["id"],
431
+ usage_percentage=usage["usage_percentage"]
432
+ )
433
+
434
+ return usage
435
+
436
+ except Exception as e:
437
+ logger.error("get_usage_failed", error=str(e))
438
+ raise HTTPException(status_code=500, detail="Failed to get usage statistics")
439
+
440
+
441
+ @router.get("/analytics")
442
+ async def get_storage_analytics(
443
+ days: int = Query(30, ge=1, le=365, description="Number of days to analyze"),
444
+ organization: dict = Depends(get_current_organization),
445
+ ):
446
+ """
447
+ Get storage analytics over time.
448
+
449
+ Returns:
450
+ - Daily storage growth
451
+ - File type breakdown
452
+ - Most accessed files
453
+ - Upload/download trends
454
+ """
455
+ # TODO: Implement analytics aggregation
456
+ raise HTTPException(status_code=501, detail="Analytics not yet implemented")