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.
- control_plane_api/LICENSE +676 -0
- control_plane_api/README.md +350 -0
- control_plane_api/__init__.py +4 -0
- control_plane_api/__version__.py +8 -0
- control_plane_api/alembic/README +1 -0
- control_plane_api/alembic/env.py +121 -0
- control_plane_api/alembic/script.py.mako +28 -0
- control_plane_api/alembic/versions/2613c65c3dbe_initial_database_setup.py +32 -0
- control_plane_api/alembic/versions/2df520d4927d_merge_heads.py +28 -0
- control_plane_api/alembic/versions/43abf98d6a01_add_paused_status_to_executions.py +73 -0
- control_plane_api/alembic/versions/6289854264cb_merge_multiple_heads.py +28 -0
- control_plane_api/alembic/versions/6a4d4dc3d8dc_generate_execution_transitions.py +50 -0
- control_plane_api/alembic/versions/87d11cf0a783_add_disconnected_status_to_worker_.py +44 -0
- control_plane_api/alembic/versions/add_ephemeral_queue_support.py +85 -0
- control_plane_api/alembic/versions/add_model_type_to_llm_models.py +31 -0
- control_plane_api/alembic/versions/add_plan_executions_table.py +114 -0
- control_plane_api/alembic/versions/add_trace_span_tables.py +154 -0
- control_plane_api/alembic/versions/add_user_info_to_traces.py +36 -0
- control_plane_api/alembic/versions/adjusting_foreign_keys.py +32 -0
- control_plane_api/alembic/versions/b4983d976db2_initial_tables.py +1128 -0
- control_plane_api/alembic/versions/d181a3b40e71_rename_custom_metadata_to_metadata_in_.py +50 -0
- control_plane_api/alembic/versions/df9117888e82_add_missing_columns.py +82 -0
- control_plane_api/alembic/versions/f25de6ad895a_missing_migrations.py +34 -0
- control_plane_api/alembic/versions/f71305fb69b9_fix_ephemeral_queue_deletion_foreign_key.py +54 -0
- control_plane_api/alembic/versions/mark_local_exec_queues_as_ephemeral.py +68 -0
- control_plane_api/alembic.ini +148 -0
- control_plane_api/api/index.py +12 -0
- control_plane_api/app/__init__.py +11 -0
- control_plane_api/app/activities/__init__.py +20 -0
- control_plane_api/app/activities/agent_activities.py +384 -0
- control_plane_api/app/activities/plan_generation_activities.py +499 -0
- control_plane_api/app/activities/team_activities.py +424 -0
- control_plane_api/app/activities/temporal_cloud_activities.py +588 -0
- control_plane_api/app/config/__init__.py +35 -0
- control_plane_api/app/config/api_config.py +469 -0
- control_plane_api/app/config/config_loader.py +224 -0
- control_plane_api/app/config/model_pricing.py +323 -0
- control_plane_api/app/config/storage_config.py +159 -0
- control_plane_api/app/config.py +115 -0
- control_plane_api/app/controllers/__init__.py +0 -0
- control_plane_api/app/controllers/execution_environment_controller.py +1315 -0
- control_plane_api/app/database.py +135 -0
- control_plane_api/app/exceptions.py +408 -0
- control_plane_api/app/lib/__init__.py +11 -0
- control_plane_api/app/lib/environment.py +65 -0
- control_plane_api/app/lib/event_bus/__init__.py +17 -0
- control_plane_api/app/lib/event_bus/base.py +136 -0
- control_plane_api/app/lib/event_bus/manager.py +335 -0
- control_plane_api/app/lib/event_bus/providers/__init__.py +6 -0
- control_plane_api/app/lib/event_bus/providers/http_provider.py +166 -0
- control_plane_api/app/lib/event_bus/providers/nats_provider.py +324 -0
- control_plane_api/app/lib/event_bus/providers/redis_provider.py +233 -0
- control_plane_api/app/lib/event_bus/providers/websocket_provider.py +497 -0
- control_plane_api/app/lib/job_executor.py +330 -0
- control_plane_api/app/lib/kubiya_client.py +293 -0
- control_plane_api/app/lib/litellm_pricing.py +166 -0
- control_plane_api/app/lib/mcp_validation.py +163 -0
- control_plane_api/app/lib/nats/__init__.py +13 -0
- control_plane_api/app/lib/nats/credentials_manager.py +288 -0
- control_plane_api/app/lib/nats/listener.py +374 -0
- control_plane_api/app/lib/planning_prompt_builder.py +153 -0
- control_plane_api/app/lib/planning_tools/__init__.py +41 -0
- control_plane_api/app/lib/planning_tools/agents.py +409 -0
- control_plane_api/app/lib/planning_tools/agno_toolkit.py +836 -0
- control_plane_api/app/lib/planning_tools/base.py +119 -0
- control_plane_api/app/lib/planning_tools/cognitive_memory_tools.py +403 -0
- control_plane_api/app/lib/planning_tools/context_graph_tools.py +545 -0
- control_plane_api/app/lib/planning_tools/environments.py +218 -0
- control_plane_api/app/lib/planning_tools/knowledge.py +204 -0
- control_plane_api/app/lib/planning_tools/models.py +93 -0
- control_plane_api/app/lib/planning_tools/planning_service.py +646 -0
- control_plane_api/app/lib/planning_tools/resources.py +242 -0
- control_plane_api/app/lib/planning_tools/teams.py +334 -0
- control_plane_api/app/lib/policy_enforcer_client.py +1016 -0
- control_plane_api/app/lib/redis_client.py +803 -0
- control_plane_api/app/lib/sqlalchemy_utils.py +486 -0
- control_plane_api/app/lib/state_transition_tools/__init__.py +7 -0
- control_plane_api/app/lib/state_transition_tools/execution_context.py +388 -0
- control_plane_api/app/lib/storage/__init__.py +20 -0
- control_plane_api/app/lib/storage/base_provider.py +274 -0
- control_plane_api/app/lib/storage/provider_factory.py +157 -0
- control_plane_api/app/lib/storage/vercel_blob_provider.py +468 -0
- control_plane_api/app/lib/supabase.py +71 -0
- control_plane_api/app/lib/supabase_utils.py +138 -0
- control_plane_api/app/lib/task_planning/__init__.py +138 -0
- control_plane_api/app/lib/task_planning/agent_factory.py +308 -0
- control_plane_api/app/lib/task_planning/agents.py +389 -0
- control_plane_api/app/lib/task_planning/cache.py +218 -0
- control_plane_api/app/lib/task_planning/entity_resolver.py +273 -0
- control_plane_api/app/lib/task_planning/helpers.py +293 -0
- control_plane_api/app/lib/task_planning/hooks.py +474 -0
- control_plane_api/app/lib/task_planning/models.py +503 -0
- control_plane_api/app/lib/task_planning/plan_validator.py +166 -0
- control_plane_api/app/lib/task_planning/planning_workflow.py +2911 -0
- control_plane_api/app/lib/task_planning/runner.py +656 -0
- control_plane_api/app/lib/task_planning/streaming_hook.py +213 -0
- control_plane_api/app/lib/task_planning/workflow.py +424 -0
- control_plane_api/app/lib/templating/__init__.py +88 -0
- control_plane_api/app/lib/templating/compiler.py +278 -0
- control_plane_api/app/lib/templating/engine.py +178 -0
- control_plane_api/app/lib/templating/parsers/__init__.py +29 -0
- control_plane_api/app/lib/templating/parsers/base.py +96 -0
- control_plane_api/app/lib/templating/parsers/env.py +85 -0
- control_plane_api/app/lib/templating/parsers/graph.py +112 -0
- control_plane_api/app/lib/templating/parsers/secret.py +87 -0
- control_plane_api/app/lib/templating/parsers/simple.py +81 -0
- control_plane_api/app/lib/templating/resolver.py +366 -0
- control_plane_api/app/lib/templating/types.py +214 -0
- control_plane_api/app/lib/templating/validator.py +201 -0
- control_plane_api/app/lib/temporal_client.py +232 -0
- control_plane_api/app/lib/temporal_credentials_cache.py +178 -0
- control_plane_api/app/lib/temporal_credentials_service.py +203 -0
- control_plane_api/app/lib/validation/__init__.py +24 -0
- control_plane_api/app/lib/validation/runtime_validation.py +388 -0
- control_plane_api/app/main.py +531 -0
- control_plane_api/app/middleware/__init__.py +10 -0
- control_plane_api/app/middleware/auth.py +645 -0
- control_plane_api/app/middleware/exception_handler.py +267 -0
- control_plane_api/app/middleware/prometheus_middleware.py +173 -0
- control_plane_api/app/middleware/rate_limiting.py +384 -0
- control_plane_api/app/middleware/request_id.py +202 -0
- control_plane_api/app/models/__init__.py +40 -0
- control_plane_api/app/models/agent.py +90 -0
- control_plane_api/app/models/analytics.py +206 -0
- control_plane_api/app/models/associations.py +107 -0
- control_plane_api/app/models/auth_user.py +73 -0
- control_plane_api/app/models/context.py +161 -0
- control_plane_api/app/models/custom_integration.py +99 -0
- control_plane_api/app/models/environment.py +64 -0
- control_plane_api/app/models/execution.py +125 -0
- control_plane_api/app/models/execution_transition.py +50 -0
- control_plane_api/app/models/job.py +159 -0
- control_plane_api/app/models/llm_model.py +78 -0
- control_plane_api/app/models/orchestration.py +66 -0
- control_plane_api/app/models/plan_execution.py +102 -0
- control_plane_api/app/models/presence.py +49 -0
- control_plane_api/app/models/project.py +61 -0
- control_plane_api/app/models/project_management.py +85 -0
- control_plane_api/app/models/session.py +29 -0
- control_plane_api/app/models/skill.py +155 -0
- control_plane_api/app/models/system_tables.py +43 -0
- control_plane_api/app/models/task_planning.py +372 -0
- control_plane_api/app/models/team.py +86 -0
- control_plane_api/app/models/trace.py +257 -0
- control_plane_api/app/models/user_profile.py +54 -0
- control_plane_api/app/models/worker.py +221 -0
- control_plane_api/app/models/workflow.py +161 -0
- control_plane_api/app/models/workspace.py +50 -0
- control_plane_api/app/observability/__init__.py +177 -0
- control_plane_api/app/observability/context_logging.py +475 -0
- control_plane_api/app/observability/decorators.py +337 -0
- control_plane_api/app/observability/local_span_processor.py +702 -0
- control_plane_api/app/observability/metrics.py +303 -0
- control_plane_api/app/observability/middleware.py +246 -0
- control_plane_api/app/observability/optional.py +115 -0
- control_plane_api/app/observability/tracing.py +382 -0
- control_plane_api/app/policies/README.md +149 -0
- control_plane_api/app/policies/approved_users.rego +62 -0
- control_plane_api/app/policies/business_hours.rego +51 -0
- control_plane_api/app/policies/rate_limiting.rego +100 -0
- control_plane_api/app/policies/tool_enforcement/README.md +336 -0
- control_plane_api/app/policies/tool_enforcement/bash_command_validation.rego +71 -0
- control_plane_api/app/policies/tool_enforcement/business_hours_enforcement.rego +82 -0
- control_plane_api/app/policies/tool_enforcement/mcp_tool_allowlist.rego +58 -0
- control_plane_api/app/policies/tool_enforcement/production_safeguards.rego +80 -0
- control_plane_api/app/policies/tool_enforcement/role_based_tool_access.rego +44 -0
- control_plane_api/app/policies/tool_restrictions.rego +86 -0
- control_plane_api/app/routers/__init__.py +4 -0
- control_plane_api/app/routers/agents.py +382 -0
- control_plane_api/app/routers/agents_v2.py +1598 -0
- control_plane_api/app/routers/analytics.py +1310 -0
- control_plane_api/app/routers/auth.py +59 -0
- control_plane_api/app/routers/client_config.py +57 -0
- control_plane_api/app/routers/context_graph.py +561 -0
- control_plane_api/app/routers/context_manager.py +577 -0
- control_plane_api/app/routers/custom_integrations.py +490 -0
- control_plane_api/app/routers/enforcer.py +132 -0
- control_plane_api/app/routers/environment_context.py +252 -0
- control_plane_api/app/routers/environments.py +761 -0
- control_plane_api/app/routers/execution_environment.py +847 -0
- control_plane_api/app/routers/executions/__init__.py +28 -0
- control_plane_api/app/routers/executions/router.py +286 -0
- control_plane_api/app/routers/executions/services/__init__.py +22 -0
- control_plane_api/app/routers/executions/services/demo_worker_health.py +156 -0
- control_plane_api/app/routers/executions/services/status_service.py +420 -0
- control_plane_api/app/routers/executions/services/test_worker_health.py +480 -0
- control_plane_api/app/routers/executions/services/worker_health.py +514 -0
- control_plane_api/app/routers/executions/streaming/__init__.py +22 -0
- control_plane_api/app/routers/executions/streaming/deduplication.py +352 -0
- control_plane_api/app/routers/executions/streaming/event_buffer.py +353 -0
- control_plane_api/app/routers/executions/streaming/event_formatter.py +964 -0
- control_plane_api/app/routers/executions/streaming/history_loader.py +588 -0
- control_plane_api/app/routers/executions/streaming/live_source.py +693 -0
- control_plane_api/app/routers/executions/streaming/streamer.py +849 -0
- control_plane_api/app/routers/executions.py +4888 -0
- control_plane_api/app/routers/health.py +165 -0
- control_plane_api/app/routers/health_v2.py +394 -0
- control_plane_api/app/routers/integration_templates.py +496 -0
- control_plane_api/app/routers/integrations.py +287 -0
- control_plane_api/app/routers/jobs.py +1809 -0
- control_plane_api/app/routers/metrics.py +517 -0
- control_plane_api/app/routers/models.py +82 -0
- control_plane_api/app/routers/models_v2.py +628 -0
- control_plane_api/app/routers/plan_executions.py +1481 -0
- control_plane_api/app/routers/plan_generation_async.py +304 -0
- control_plane_api/app/routers/policies.py +669 -0
- control_plane_api/app/routers/presence.py +234 -0
- control_plane_api/app/routers/projects.py +987 -0
- control_plane_api/app/routers/runners.py +379 -0
- control_plane_api/app/routers/runtimes.py +172 -0
- control_plane_api/app/routers/secrets.py +171 -0
- control_plane_api/app/routers/skills.py +1010 -0
- control_plane_api/app/routers/skills_definitions.py +140 -0
- control_plane_api/app/routers/storage.py +456 -0
- control_plane_api/app/routers/task_planning.py +611 -0
- control_plane_api/app/routers/task_queues.py +650 -0
- control_plane_api/app/routers/team_context.py +274 -0
- control_plane_api/app/routers/teams.py +1747 -0
- control_plane_api/app/routers/templates.py +248 -0
- control_plane_api/app/routers/traces.py +571 -0
- control_plane_api/app/routers/websocket_client.py +479 -0
- control_plane_api/app/routers/websocket_executions_status.py +437 -0
- control_plane_api/app/routers/websocket_gateway.py +323 -0
- control_plane_api/app/routers/websocket_traces.py +576 -0
- control_plane_api/app/routers/worker_queues.py +2555 -0
- control_plane_api/app/routers/worker_websocket.py +419 -0
- control_plane_api/app/routers/workers.py +1004 -0
- control_plane_api/app/routers/workflows.py +204 -0
- control_plane_api/app/runtimes/__init__.py +6 -0
- control_plane_api/app/runtimes/validation.py +344 -0
- control_plane_api/app/schemas/__init__.py +1 -0
- control_plane_api/app/schemas/job_schemas.py +302 -0
- control_plane_api/app/schemas/mcp_schemas.py +311 -0
- control_plane_api/app/schemas/template_schemas.py +133 -0
- control_plane_api/app/schemas/trace_schemas.py +168 -0
- control_plane_api/app/schemas/worker_queue_observability_schemas.py +165 -0
- control_plane_api/app/services/__init__.py +1 -0
- control_plane_api/app/services/agno_planning_strategy.py +233 -0
- control_plane_api/app/services/agno_service.py +838 -0
- control_plane_api/app/services/claude_code_planning_service.py +203 -0
- control_plane_api/app/services/context_graph_client.py +224 -0
- control_plane_api/app/services/custom_integration_service.py +415 -0
- control_plane_api/app/services/integration_resolution_service.py +345 -0
- control_plane_api/app/services/litellm_service.py +394 -0
- control_plane_api/app/services/plan_generator.py +79 -0
- control_plane_api/app/services/planning_strategy.py +66 -0
- control_plane_api/app/services/planning_strategy_factory.py +118 -0
- control_plane_api/app/services/policy_service.py +615 -0
- control_plane_api/app/services/state_transition_service.py +755 -0
- control_plane_api/app/services/storage_service.py +593 -0
- control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
- control_plane_api/app/services/toolsets/context_graph_skill.py +432 -0
- control_plane_api/app/services/trace_retention.py +354 -0
- control_plane_api/app/services/worker_queue_metrics_service.py +190 -0
- control_plane_api/app/services/workflow_cancellation_manager.py +135 -0
- control_plane_api/app/services/workflow_operations_service.py +611 -0
- control_plane_api/app/skills/__init__.py +100 -0
- control_plane_api/app/skills/base.py +239 -0
- control_plane_api/app/skills/builtin/__init__.py +37 -0
- control_plane_api/app/skills/builtin/agent_communication/__init__.py +8 -0
- control_plane_api/app/skills/builtin/agent_communication/skill.py +246 -0
- control_plane_api/app/skills/builtin/code_ingestion/__init__.py +4 -0
- control_plane_api/app/skills/builtin/code_ingestion/skill.py +267 -0
- control_plane_api/app/skills/builtin/cognitive_memory/__init__.py +4 -0
- control_plane_api/app/skills/builtin/cognitive_memory/skill.py +174 -0
- control_plane_api/app/skills/builtin/contextual_awareness/__init__.py +4 -0
- control_plane_api/app/skills/builtin/contextual_awareness/skill.py +387 -0
- control_plane_api/app/skills/builtin/data_visualization/__init__.py +4 -0
- control_plane_api/app/skills/builtin/data_visualization/skill.py +154 -0
- control_plane_api/app/skills/builtin/docker/__init__.py +4 -0
- control_plane_api/app/skills/builtin/docker/skill.py +104 -0
- control_plane_api/app/skills/builtin/file_generation/__init__.py +4 -0
- control_plane_api/app/skills/builtin/file_generation/skill.py +94 -0
- control_plane_api/app/skills/builtin/file_system/__init__.py +4 -0
- control_plane_api/app/skills/builtin/file_system/skill.py +110 -0
- control_plane_api/app/skills/builtin/knowledge_api/__init__.py +5 -0
- control_plane_api/app/skills/builtin/knowledge_api/skill.py +124 -0
- control_plane_api/app/skills/builtin/python/__init__.py +4 -0
- control_plane_api/app/skills/builtin/python/skill.py +92 -0
- control_plane_api/app/skills/builtin/remote_filesystem/__init__.py +5 -0
- control_plane_api/app/skills/builtin/remote_filesystem/skill.py +170 -0
- control_plane_api/app/skills/builtin/shell/__init__.py +4 -0
- control_plane_api/app/skills/builtin/shell/skill.py +161 -0
- control_plane_api/app/skills/builtin/slack/__init__.py +3 -0
- control_plane_api/app/skills/builtin/slack/skill.py +302 -0
- control_plane_api/app/skills/builtin/workflow_executor/__init__.py +4 -0
- control_plane_api/app/skills/builtin/workflow_executor/skill.py +469 -0
- control_plane_api/app/skills/business_intelligence.py +189 -0
- control_plane_api/app/skills/config.py +63 -0
- control_plane_api/app/skills/loaders/__init__.py +14 -0
- control_plane_api/app/skills/loaders/base.py +73 -0
- control_plane_api/app/skills/loaders/filesystem_loader.py +199 -0
- control_plane_api/app/skills/registry.py +125 -0
- control_plane_api/app/utils/helpers.py +12 -0
- control_plane_api/app/utils/workflow_executor.py +354 -0
- control_plane_api/app/workflows/__init__.py +11 -0
- control_plane_api/app/workflows/agent_execution.py +520 -0
- control_plane_api/app/workflows/agent_execution_with_skills.py +223 -0
- control_plane_api/app/workflows/namespace_provisioning.py +326 -0
- control_plane_api/app/workflows/plan_generation.py +254 -0
- control_plane_api/app/workflows/team_execution.py +442 -0
- control_plane_api/scripts/seed_models.py +240 -0
- control_plane_api/scripts/validate_existing_tool_names.py +492 -0
- control_plane_api/shared/__init__.py +8 -0
- control_plane_api/shared/version.py +17 -0
- control_plane_api/test_deduplication.py +274 -0
- control_plane_api/test_executor_deduplication_e2e.py +309 -0
- control_plane_api/test_job_execution_e2e.py +283 -0
- control_plane_api/test_real_integration.py +193 -0
- control_plane_api/version.py +38 -0
- control_plane_api/worker/__init__.py +0 -0
- control_plane_api/worker/activities/__init__.py +0 -0
- control_plane_api/worker/activities/agent_activities.py +1585 -0
- control_plane_api/worker/activities/approval_activities.py +234 -0
- control_plane_api/worker/activities/job_activities.py +199 -0
- control_plane_api/worker/activities/runtime_activities.py +1167 -0
- control_plane_api/worker/activities/skill_activities.py +282 -0
- control_plane_api/worker/activities/team_activities.py +479 -0
- control_plane_api/worker/agent_runtime_server.py +370 -0
- control_plane_api/worker/binary_manager.py +333 -0
- control_plane_api/worker/config/__init__.py +31 -0
- control_plane_api/worker/config/worker_config.py +273 -0
- control_plane_api/worker/control_plane_client.py +1491 -0
- control_plane_api/worker/examples/analytics_integration_example.py +362 -0
- control_plane_api/worker/health_monitor.py +159 -0
- control_plane_api/worker/metrics.py +237 -0
- control_plane_api/worker/models/__init__.py +1 -0
- control_plane_api/worker/models/error_events.py +105 -0
- control_plane_api/worker/models/inputs.py +89 -0
- control_plane_api/worker/runtimes/__init__.py +35 -0
- control_plane_api/worker/runtimes/agent_runtime/runtime.py +485 -0
- control_plane_api/worker/runtimes/agno/__init__.py +34 -0
- control_plane_api/worker/runtimes/agno/config.py +248 -0
- control_plane_api/worker/runtimes/agno/hooks.py +385 -0
- control_plane_api/worker/runtimes/agno/mcp_builder.py +195 -0
- control_plane_api/worker/runtimes/agno/runtime.py +1063 -0
- control_plane_api/worker/runtimes/agno/utils.py +163 -0
- control_plane_api/worker/runtimes/base.py +979 -0
- control_plane_api/worker/runtimes/claude_code/__init__.py +38 -0
- control_plane_api/worker/runtimes/claude_code/cleanup.py +184 -0
- control_plane_api/worker/runtimes/claude_code/client_pool.py +529 -0
- control_plane_api/worker/runtimes/claude_code/config.py +829 -0
- control_plane_api/worker/runtimes/claude_code/hooks.py +482 -0
- control_plane_api/worker/runtimes/claude_code/litellm_proxy.py +1702 -0
- control_plane_api/worker/runtimes/claude_code/mcp_builder.py +467 -0
- control_plane_api/worker/runtimes/claude_code/mcp_discovery.py +558 -0
- control_plane_api/worker/runtimes/claude_code/runtime.py +1546 -0
- control_plane_api/worker/runtimes/claude_code/tool_mapper.py +403 -0
- control_plane_api/worker/runtimes/claude_code/utils.py +149 -0
- control_plane_api/worker/runtimes/factory.py +173 -0
- control_plane_api/worker/runtimes/model_utils.py +107 -0
- control_plane_api/worker/runtimes/validation.py +93 -0
- control_plane_api/worker/services/__init__.py +1 -0
- control_plane_api/worker/services/agent_communication_tools.py +908 -0
- control_plane_api/worker/services/agent_executor.py +485 -0
- control_plane_api/worker/services/agent_executor_v2.py +793 -0
- control_plane_api/worker/services/analytics_collector.py +457 -0
- control_plane_api/worker/services/analytics_service.py +464 -0
- control_plane_api/worker/services/approval_tools.py +310 -0
- control_plane_api/worker/services/approval_tools_agno.py +207 -0
- control_plane_api/worker/services/cancellation_manager.py +177 -0
- control_plane_api/worker/services/code_ingestion_tools.py +465 -0
- control_plane_api/worker/services/contextual_awareness_tools.py +405 -0
- control_plane_api/worker/services/data_visualization.py +834 -0
- control_plane_api/worker/services/event_publisher.py +531 -0
- control_plane_api/worker/services/jira_tools.py +257 -0
- control_plane_api/worker/services/remote_filesystem_tools.py +498 -0
- control_plane_api/worker/services/runtime_analytics.py +328 -0
- control_plane_api/worker/services/session_service.py +365 -0
- control_plane_api/worker/services/skill_context_enhancement.py +181 -0
- control_plane_api/worker/services/skill_factory.py +471 -0
- control_plane_api/worker/services/system_prompt_enhancement.py +410 -0
- control_plane_api/worker/services/team_executor.py +715 -0
- control_plane_api/worker/services/team_executor_v2.py +1866 -0
- control_plane_api/worker/services/tool_enforcement.py +254 -0
- control_plane_api/worker/services/workflow_executor/__init__.py +52 -0
- control_plane_api/worker/services/workflow_executor/event_processor.py +287 -0
- control_plane_api/worker/services/workflow_executor/event_publisher.py +210 -0
- control_plane_api/worker/services/workflow_executor/executors/__init__.py +15 -0
- control_plane_api/worker/services/workflow_executor/executors/base.py +270 -0
- control_plane_api/worker/services/workflow_executor/executors/json_executor.py +50 -0
- control_plane_api/worker/services/workflow_executor/executors/python_executor.py +50 -0
- control_plane_api/worker/services/workflow_executor/models.py +142 -0
- control_plane_api/worker/services/workflow_executor_tools.py +1748 -0
- control_plane_api/worker/skills/__init__.py +12 -0
- control_plane_api/worker/skills/builtin/context_graph_search/README.md +213 -0
- control_plane_api/worker/skills/builtin/context_graph_search/__init__.py +5 -0
- control_plane_api/worker/skills/builtin/context_graph_search/agno_impl.py +808 -0
- control_plane_api/worker/skills/builtin/context_graph_search/skill.yaml +67 -0
- control_plane_api/worker/skills/builtin/contextual_awareness/__init__.py +4 -0
- control_plane_api/worker/skills/builtin/contextual_awareness/agno_impl.py +62 -0
- control_plane_api/worker/skills/builtin/data_visualization/agno_impl.py +18 -0
- control_plane_api/worker/skills/builtin/data_visualization/skill.yaml +84 -0
- control_plane_api/worker/skills/builtin/docker/agno_impl.py +65 -0
- control_plane_api/worker/skills/builtin/docker/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/file_generation/agno_impl.py +47 -0
- control_plane_api/worker/skills/builtin/file_generation/skill.yaml +64 -0
- control_plane_api/worker/skills/builtin/file_system/agno_impl.py +32 -0
- control_plane_api/worker/skills/builtin/file_system/skill.yaml +54 -0
- control_plane_api/worker/skills/builtin/knowledge_api/__init__.py +4 -0
- control_plane_api/worker/skills/builtin/knowledge_api/agno_impl.py +50 -0
- control_plane_api/worker/skills/builtin/knowledge_api/skill.yaml +66 -0
- control_plane_api/worker/skills/builtin/python/agno_impl.py +25 -0
- control_plane_api/worker/skills/builtin/python/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/schema_fix_mixin.py +260 -0
- control_plane_api/worker/skills/builtin/shell/agno_impl.py +31 -0
- control_plane_api/worker/skills/builtin/shell/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/slack/__init__.py +3 -0
- control_plane_api/worker/skills/builtin/slack/agno_impl.py +1282 -0
- control_plane_api/worker/skills/builtin/slack/skill.yaml +276 -0
- control_plane_api/worker/skills/builtin/workflow_executor/agno_impl.py +62 -0
- control_plane_api/worker/skills/builtin/workflow_executor/skill.yaml +79 -0
- control_plane_api/worker/skills/loaders/__init__.py +5 -0
- control_plane_api/worker/skills/loaders/base.py +23 -0
- control_plane_api/worker/skills/loaders/filesystem_loader.py +357 -0
- control_plane_api/worker/skills/registry.py +208 -0
- control_plane_api/worker/tests/__init__.py +1 -0
- control_plane_api/worker/tests/conftest.py +12 -0
- control_plane_api/worker/tests/e2e/__init__.py +0 -0
- control_plane_api/worker/tests/e2e/test_context_graph_real_api.py +338 -0
- control_plane_api/worker/tests/e2e/test_context_graph_templates_e2e.py +523 -0
- control_plane_api/worker/tests/e2e/test_enforcement_e2e.py +344 -0
- control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
- control_plane_api/worker/tests/e2e/test_single_execution_mode.py +656 -0
- control_plane_api/worker/tests/integration/__init__.py +0 -0
- control_plane_api/worker/tests/integration/test_builtin_skills_fixes.py +245 -0
- control_plane_api/worker/tests/integration/test_context_graph_search_integration.py +365 -0
- control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
- control_plane_api/worker/tests/integration/test_hook_enforcement_integration.py +579 -0
- control_plane_api/worker/tests/integration/test_scheduled_job_workflow.py +237 -0
- control_plane_api/worker/tests/integration/test_system_prompt_enhancement_integration.py +343 -0
- control_plane_api/worker/tests/unit/__init__.py +0 -0
- control_plane_api/worker/tests/unit/test_builtin_skill_autoload.py +396 -0
- control_plane_api/worker/tests/unit/test_context_graph_search.py +450 -0
- control_plane_api/worker/tests/unit/test_context_graph_templates.py +403 -0
- control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
- control_plane_api/worker/tests/unit/test_control_plane_client_jobs.py +345 -0
- control_plane_api/worker/tests/unit/test_job_activities.py +353 -0
- control_plane_api/worker/tests/unit/test_skill_context_enhancement.py +321 -0
- control_plane_api/worker/tests/unit/test_system_prompt_enhancement.py +415 -0
- control_plane_api/worker/tests/unit/test_tool_enforcement.py +324 -0
- control_plane_api/worker/utils/__init__.py +1 -0
- control_plane_api/worker/utils/chunk_batcher.py +330 -0
- control_plane_api/worker/utils/environment.py +65 -0
- control_plane_api/worker/utils/error_publisher.py +260 -0
- control_plane_api/worker/utils/event_batcher.py +256 -0
- control_plane_api/worker/utils/logging_config.py +335 -0
- control_plane_api/worker/utils/logging_helper.py +326 -0
- control_plane_api/worker/utils/parameter_validator.py +120 -0
- control_plane_api/worker/utils/retry_utils.py +60 -0
- control_plane_api/worker/utils/streaming_utils.py +665 -0
- control_plane_api/worker/utils/tool_validation.py +332 -0
- control_plane_api/worker/utils/workspace_manager.py +163 -0
- control_plane_api/worker/websocket_client.py +393 -0
- control_plane_api/worker/worker.py +1297 -0
- control_plane_api/worker/workflows/__init__.py +0 -0
- control_plane_api/worker/workflows/agent_execution.py +909 -0
- control_plane_api/worker/workflows/scheduled_job_wrapper.py +332 -0
- control_plane_api/worker/workflows/team_execution.py +611 -0
- kubiya_control_plane_api-0.9.15.dist-info/METADATA +354 -0
- kubiya_control_plane_api-0.9.15.dist-info/RECORD +479 -0
- kubiya_control_plane_api-0.9.15.dist-info/WHEEL +5 -0
- kubiya_control_plane_api-0.9.15.dist-info/entry_points.txt +5 -0
- kubiya_control_plane_api-0.9.15.dist-info/licenses/LICENSE +676 -0
- kubiya_control_plane_api-0.9.15.dist-info/top_level.txt +3 -0
- scripts/__init__.py +1 -0
- scripts/migrations.py +39 -0
- scripts/seed_worker_queues.py +128 -0
- scripts/setup_agent_runtime.py +142 -0
- worker_internal/__init__.py +1 -0
- worker_internal/planner/__init__.py +1 -0
- worker_internal/planner/activities.py +1499 -0
- worker_internal/planner/agent_tools.py +197 -0
- worker_internal/planner/event_models.py +148 -0
- worker_internal/planner/event_publisher.py +67 -0
- worker_internal/planner/models.py +199 -0
- worker_internal/planner/retry_logic.py +134 -0
- worker_internal/planner/worker.py +300 -0
- 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")
|