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,469 @@
|
|
|
1
|
+
"""
|
|
2
|
+
API-specific configuration.
|
|
3
|
+
|
|
4
|
+
This module contains settings specific to the Control Plane API server.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
8
|
+
from pydantic import Field, validator, model_validator, AliasChoices
|
|
9
|
+
from typing import List, Optional, Dict, Any
|
|
10
|
+
import secrets
|
|
11
|
+
import os
|
|
12
|
+
from control_plane_api.version import get_sdk_version
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class APIConfig(BaseSettings):
|
|
16
|
+
"""Configuration for Control Plane API server."""
|
|
17
|
+
|
|
18
|
+
# ==================== API Server Settings ====================
|
|
19
|
+
|
|
20
|
+
api_host: str = Field(
|
|
21
|
+
default="0.0.0.0",
|
|
22
|
+
description="API server host",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
api_port: int = Field(
|
|
26
|
+
default=8000,
|
|
27
|
+
description="API server port",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
api_workers: int = Field(
|
|
31
|
+
default=4,
|
|
32
|
+
description="Number of API worker processes",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
api_title: str = Field(
|
|
36
|
+
default="Agent Control Plane API",
|
|
37
|
+
description="API title for documentation",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
api_version: str = Field(
|
|
41
|
+
default_factory=get_sdk_version,
|
|
42
|
+
description="API version (dynamically read from package metadata)",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
api_description: str = Field(
|
|
46
|
+
default="Multi-tenant agent orchestration with Temporal workflows",
|
|
47
|
+
description="API description for documentation",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# ==================== Environment ====================
|
|
51
|
+
|
|
52
|
+
environment: str = Field(
|
|
53
|
+
default="development",
|
|
54
|
+
description="Environment (development, staging, production)",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
debug: bool = Field(
|
|
58
|
+
default=False,
|
|
59
|
+
description="Debug mode",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@validator("debug", pre=True)
|
|
63
|
+
def set_debug_from_env(cls, v, values):
|
|
64
|
+
"""Set debug based on environment if not explicitly set."""
|
|
65
|
+
if v is None:
|
|
66
|
+
env = values.get("environment", "development")
|
|
67
|
+
return env == "development"
|
|
68
|
+
return v
|
|
69
|
+
|
|
70
|
+
# ==================== Database Settings ====================
|
|
71
|
+
|
|
72
|
+
database_url: Optional[str] = Field(
|
|
73
|
+
default=None,
|
|
74
|
+
description="PostgreSQL database URL",
|
|
75
|
+
validation_alias=AliasChoices("DATABASE_URL", "database_url"),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
supabase_url: Optional[str] = Field(
|
|
79
|
+
default=None,
|
|
80
|
+
description="Supabase project URL",
|
|
81
|
+
validation_alias=AliasChoices("SUPABASE_URL", "supabase_url"),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
supabase_service_key: Optional[str] = Field(
|
|
85
|
+
default=None,
|
|
86
|
+
description="Supabase service role key",
|
|
87
|
+
validation_alias=AliasChoices("SUPABASE_SERVICE_KEY", "supabase_service_key"),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
supabase_anon_key: Optional[str] = Field(
|
|
91
|
+
default=None,
|
|
92
|
+
description="Supabase anonymous key",
|
|
93
|
+
validation_alias=AliasChoices("SUPABASE_ANON_KEY", "supabase_anon_key"),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
database_pool_size: int = Field(
|
|
97
|
+
default=20,
|
|
98
|
+
description="Database connection pool size",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
database_max_overflow: int = Field(
|
|
102
|
+
default=40,
|
|
103
|
+
description="Maximum overflow for database pool",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
database_pool_timeout: float = Field(
|
|
107
|
+
default=30.0,
|
|
108
|
+
description="Database pool timeout in seconds",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
@model_validator(mode='after')
|
|
112
|
+
def validate_database_config(self):
|
|
113
|
+
"""Ensure we have either DATABASE_URL or Supabase configuration."""
|
|
114
|
+
# Always try to set database_url from Supabase env vars if not already set
|
|
115
|
+
if not self.database_url:
|
|
116
|
+
supabase_db_url = (
|
|
117
|
+
os.environ.get("SUPABASE_POSTGRES_URL") or
|
|
118
|
+
os.environ.get("SUPABASE_POSTGRES_PRISMA_URL") or
|
|
119
|
+
os.environ.get("SUPABASE_DB_URL")
|
|
120
|
+
)
|
|
121
|
+
if supabase_db_url:
|
|
122
|
+
# Fix URL format for SQLAlchemy 2.0+
|
|
123
|
+
if supabase_db_url.startswith("postgres://"):
|
|
124
|
+
supabase_db_url = supabase_db_url.replace("postgres://", "postgresql://", 1)
|
|
125
|
+
# Remove invalid Supabase pooler parameters that SQLAlchemy doesn't understand
|
|
126
|
+
supabase_db_url = supabase_db_url.replace("&supa=base-pooler.x", "")
|
|
127
|
+
self.database_url = supabase_db_url
|
|
128
|
+
elif not (self.supabase_url and self.supabase_service_key) and self.environment != "development":
|
|
129
|
+
raise ValueError(
|
|
130
|
+
"Either DATABASE_URL or Supabase configuration (SUPABASE_URL and SUPABASE_SERVICE_KEY) must be provided"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Fix postgres:// to postgresql:// if needed and remove invalid params
|
|
134
|
+
if self.database_url:
|
|
135
|
+
if self.database_url.startswith("postgres://"):
|
|
136
|
+
self.database_url = self.database_url.replace("postgres://", "postgresql://", 1)
|
|
137
|
+
# Remove invalid Supabase pooler parameters from DATABASE_URL
|
|
138
|
+
self.database_url = self.database_url.replace("&supa=base-pooler.x", "")
|
|
139
|
+
|
|
140
|
+
return self
|
|
141
|
+
|
|
142
|
+
# ==================== Redis Settings ====================
|
|
143
|
+
|
|
144
|
+
redis_url: str = Field(
|
|
145
|
+
default="redis://localhost:6379/0",
|
|
146
|
+
description="Redis connection URL",
|
|
147
|
+
validation_alias=AliasChoices("REDIS_URL", "redis_url"),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
redis_host: Optional[str] = Field(
|
|
151
|
+
default=None,
|
|
152
|
+
description="Redis host (overrides URL)",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
redis_port: int = Field(
|
|
156
|
+
default=6379,
|
|
157
|
+
description="Redis port",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
redis_password: Optional[str] = Field(
|
|
161
|
+
default=None,
|
|
162
|
+
description="Redis password",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
redis_db: int = Field(
|
|
166
|
+
default=0,
|
|
167
|
+
description="Redis database number",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
redis_pool_size: int = Field(
|
|
171
|
+
default=10,
|
|
172
|
+
description="Redis connection pool size",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# ==================== Temporal Settings ====================
|
|
176
|
+
|
|
177
|
+
temporal_host: str = Field(
|
|
178
|
+
default="localhost:7233",
|
|
179
|
+
description="Temporal server host:port",
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
temporal_namespace: str = Field(
|
|
183
|
+
default="default",
|
|
184
|
+
description="Temporal namespace",
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
temporal_client_cert_path: Optional[str] = Field(
|
|
188
|
+
default=None,
|
|
189
|
+
description="Path to Temporal client certificate",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
temporal_client_key_path: Optional[str] = Field(
|
|
193
|
+
default=None,
|
|
194
|
+
description="Path to Temporal client key",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# ==================== Security Settings ====================
|
|
198
|
+
|
|
199
|
+
secret_key: str = Field(
|
|
200
|
+
default_factory=lambda: secrets.token_urlsafe(32),
|
|
201
|
+
description="Secret key for JWT signing",
|
|
202
|
+
validation_alias=AliasChoices("SECRET_KEY", "secret_key"),
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
algorithm: str = Field(
|
|
206
|
+
default="HS256",
|
|
207
|
+
description="JWT signing algorithm",
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
access_token_expire_minutes: int = Field(
|
|
211
|
+
default=30,
|
|
212
|
+
description="Access token expiration in minutes",
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
refresh_token_expire_days: int = Field(
|
|
216
|
+
default=30,
|
|
217
|
+
description="Refresh token expiration in days",
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# ==================== CORS Settings ====================
|
|
221
|
+
|
|
222
|
+
cors_origins: List[str] = Field(
|
|
223
|
+
default=["*"],
|
|
224
|
+
description="Allowed CORS origins",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
cors_allow_credentials: bool = Field(
|
|
228
|
+
default=True,
|
|
229
|
+
description="Allow credentials in CORS requests",
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
cors_allow_methods: List[str] = Field(
|
|
233
|
+
default=["*"],
|
|
234
|
+
description="Allowed CORS methods",
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
cors_allow_headers: List[str] = Field(
|
|
238
|
+
default=["*"],
|
|
239
|
+
description="Allowed CORS headers",
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
@validator("cors_origins", pre=True)
|
|
243
|
+
def validate_cors_origins(cls, v, values):
|
|
244
|
+
"""Validate CORS origins for production."""
|
|
245
|
+
# Allow environment variable to override default
|
|
246
|
+
if v is None or (isinstance(v, list) and len(v) == 1 and v[0] == "*"):
|
|
247
|
+
# Check if we're in production
|
|
248
|
+
env = values.get("environment", "development")
|
|
249
|
+
if env == "production":
|
|
250
|
+
# In production, use specific origins unless explicitly overridden
|
|
251
|
+
return [
|
|
252
|
+
"https://agent-control-plane.vercel.app",
|
|
253
|
+
"https://*.vercel.app",
|
|
254
|
+
"http://localhost:3000",
|
|
255
|
+
"http://localhost:8000",
|
|
256
|
+
]
|
|
257
|
+
return v
|
|
258
|
+
|
|
259
|
+
# ==================== External Services ====================
|
|
260
|
+
|
|
261
|
+
kubiya_api_base: str = Field(
|
|
262
|
+
default="https://api.kubiya.ai",
|
|
263
|
+
description="Kubiya API base URL",
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
kubiya_api_key: Optional[str] = Field(
|
|
267
|
+
default=None,
|
|
268
|
+
description="Kubiya API key",
|
|
269
|
+
validation_alias=AliasChoices("KUBIYA_API_KEY", "kubiya_api_key"),
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
litellm_api_base: str = Field(
|
|
273
|
+
default="https://llm-proxy.kubiya.ai",
|
|
274
|
+
description="LiteLLM proxy base URL",
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
litellm_api_key: Optional[str] = Field(
|
|
278
|
+
default=None,
|
|
279
|
+
description="LiteLLM API key",
|
|
280
|
+
validation_alias=AliasChoices("LITELLM_API_KEY", "litellm_api_key"),
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
litellm_default_model: str = Field(
|
|
284
|
+
default="kubiya/claude-sonnet-4",
|
|
285
|
+
description="Default LLM model",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
litellm_timeout: int = Field(
|
|
289
|
+
default=300,
|
|
290
|
+
description="LiteLLM request timeout in seconds",
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
litellm_models_cache_ttl: int = Field(
|
|
294
|
+
default=300,
|
|
295
|
+
description="Cache TTL for LiteLLM models list in seconds (default 5 minutes)",
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# ==================== Context Graph Settings ====================
|
|
299
|
+
|
|
300
|
+
context_graph_api_base: str = Field(
|
|
301
|
+
default="https://graph.kubiya.ai",
|
|
302
|
+
description="Context Graph API base URL",
|
|
303
|
+
validation_alias=AliasChoices("CONTEXT_GRAPH_API_BASE", "context_graph_api_base"),
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
context_graph_api_timeout: int = Field(
|
|
307
|
+
default=120, # Increased for semantic search operations
|
|
308
|
+
description="Context Graph API request timeout in seconds",
|
|
309
|
+
validation_alias=AliasChoices("CONTEXT_GRAPH_API_TIMEOUT", "context_graph_api_timeout"),
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
# ==================== Logging Settings ====================
|
|
313
|
+
|
|
314
|
+
log_level: str = Field(
|
|
315
|
+
default="INFO",
|
|
316
|
+
description="Logging level",
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
log_format: str = Field(
|
|
320
|
+
default="json",
|
|
321
|
+
description="Log format (json or text)",
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
# ==================== Monitoring Settings ====================
|
|
325
|
+
|
|
326
|
+
metrics_enabled: bool = Field(
|
|
327
|
+
default=True,
|
|
328
|
+
description="Enable Prometheus metrics",
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
tracing_enabled: bool = Field(
|
|
332
|
+
default=False,
|
|
333
|
+
description="Enable OpenTelemetry tracing",
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
otlp_endpoint: Optional[str] = Field(
|
|
337
|
+
default=None,
|
|
338
|
+
description="OpenTelemetry collector endpoint",
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
sentry_dsn: Optional[str] = Field(
|
|
342
|
+
default=None,
|
|
343
|
+
description="Sentry DSN for error reporting",
|
|
344
|
+
validation_alias=AliasChoices("SENTRY_DSN", "sentry_dsn"),
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# ==================== Rate Limiting ====================
|
|
348
|
+
|
|
349
|
+
rate_limit_enabled: bool = Field(
|
|
350
|
+
default=True,
|
|
351
|
+
description="Enable rate limiting",
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
rate_limit_requests_per_minute: int = Field(
|
|
355
|
+
default=60,
|
|
356
|
+
description="Default requests per minute limit",
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
rate_limit_burst_size: int = Field(
|
|
360
|
+
default=10,
|
|
361
|
+
description="Burst size for rate limiting",
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
# ==================== Event Bus Settings ====================
|
|
365
|
+
|
|
366
|
+
event_bus: Optional[Dict[str, Any]] = Field(
|
|
367
|
+
default=None,
|
|
368
|
+
description="Event bus configuration for multi-provider event publishing",
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
# ==================== OpenTelemetry (OTEL) Settings ====================
|
|
372
|
+
|
|
373
|
+
OTEL_ENABLED: bool = Field(
|
|
374
|
+
default=True,
|
|
375
|
+
description="Enable OpenTelemetry distributed tracing",
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: Optional[str] = Field(
|
|
379
|
+
default=None,
|
|
380
|
+
description="OTLP exporter endpoint (e.g., http://localhost:4317 for gRPC)",
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
OTEL_EXPORTER_OTLP_PROTOCOL: str = Field(
|
|
384
|
+
default="grpc",
|
|
385
|
+
description="OTLP exporter protocol: 'grpc' or 'http'",
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
OTEL_SERVICE_NAME: str = Field(
|
|
389
|
+
default="agent-control-plane",
|
|
390
|
+
description="Service name for telemetry",
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
OTEL_RESOURCE_ATTRIBUTES: str = Field(
|
|
394
|
+
default="",
|
|
395
|
+
description="Additional resource attributes (format: key1=value1,key2=value2)",
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
OTEL_TRACES_SAMPLER: str = Field(
|
|
399
|
+
default="parentbased_always_on",
|
|
400
|
+
description="Trace sampler: parentbased_always_on, parentbased_traceidratio, etc.",
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
OTEL_TRACES_SAMPLER_ARG: Optional[float] = Field(
|
|
404
|
+
default=None,
|
|
405
|
+
description="Sampler argument (e.g., 0.1 for 10% sampling with traceidratio)",
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
# Local Trace Storage Settings (for observability UI)
|
|
409
|
+
OTEL_LOCAL_STORAGE_ENABLED: bool = Field(
|
|
410
|
+
default=True,
|
|
411
|
+
description="Store traces locally in PostgreSQL for observability UI",
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
OTEL_LOCAL_STORAGE_BATCH_SIZE: int = Field(
|
|
415
|
+
default=100,
|
|
416
|
+
description="Number of spans to batch before inserting to database",
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
OTEL_LOCAL_STORAGE_FLUSH_INTERVAL: int = Field(
|
|
420
|
+
default=1000,
|
|
421
|
+
description="Max time (ms) before flushing batch",
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
OTEL_LOCAL_STORAGE_RETENTION_DAYS: int = Field(
|
|
425
|
+
default=30,
|
|
426
|
+
description="Days to retain traces",
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
model_config = SettingsConfigDict(
|
|
430
|
+
env_file=".env.local",
|
|
431
|
+
env_file_encoding="utf-8",
|
|
432
|
+
case_sensitive=False,
|
|
433
|
+
extra="ignore",
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
@classmethod
|
|
437
|
+
def from_yaml_and_env(cls, config_path: Optional[str] = None) -> "APIConfig":
|
|
438
|
+
"""
|
|
439
|
+
Load configuration from YAML file and merge with environment variables.
|
|
440
|
+
|
|
441
|
+
Priority: Environment variables > YAML file > Defaults
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
config_path: Optional path to YAML config file
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
APIConfig instance with merged configuration
|
|
448
|
+
|
|
449
|
+
Example YAML:
|
|
450
|
+
event_bus:
|
|
451
|
+
http:
|
|
452
|
+
enabled: true
|
|
453
|
+
base_url: ${CONTROL_PLANE_URL}
|
|
454
|
+
websocket:
|
|
455
|
+
enabled: true
|
|
456
|
+
redis:
|
|
457
|
+
enabled: true
|
|
458
|
+
redis_url: ${REDIS_URL}
|
|
459
|
+
nats:
|
|
460
|
+
enabled: false
|
|
461
|
+
"""
|
|
462
|
+
from control_plane_api.app.config.config_loader import load_config_file
|
|
463
|
+
|
|
464
|
+
# Load YAML config (empty dict if no file found)
|
|
465
|
+
yaml_config = load_config_file(config_path)
|
|
466
|
+
|
|
467
|
+
# Pydantic will merge YAML config with environment variables
|
|
468
|
+
# Environment variables take precedence
|
|
469
|
+
return cls(**yaml_config)
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""YAML configuration file loader with environment variable substitution."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Dict, Any
|
|
7
|
+
import structlog
|
|
8
|
+
|
|
9
|
+
logger = structlog.get_logger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ConfigFileLoader:
|
|
13
|
+
"""Load and merge YAML configuration with environment variables."""
|
|
14
|
+
|
|
15
|
+
# Pattern to match ${VAR_NAME} or ${VAR_NAME:default}
|
|
16
|
+
ENV_VAR_PATTERN = re.compile(r"\$\{([^}:]+)(?::([^}]*))?\}")
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def _substitute_env_vars(value: Any) -> Any:
|
|
20
|
+
"""
|
|
21
|
+
Recursively substitute environment variables in configuration values.
|
|
22
|
+
|
|
23
|
+
Supports:
|
|
24
|
+
- ${VAR_NAME} - Required variable, fails if not set
|
|
25
|
+
- ${VAR_NAME:default} - Optional variable with default value
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
value: Configuration value (str, dict, list, or other)
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Value with environment variables substituted
|
|
32
|
+
"""
|
|
33
|
+
if isinstance(value, str):
|
|
34
|
+
# Substitute all ${VAR} occurrences in string
|
|
35
|
+
def replacer(match):
|
|
36
|
+
var_name = match.group(1)
|
|
37
|
+
default_value = match.group(2) # May be None
|
|
38
|
+
|
|
39
|
+
env_value = os.getenv(var_name)
|
|
40
|
+
|
|
41
|
+
if env_value is not None:
|
|
42
|
+
return env_value
|
|
43
|
+
elif default_value is not None:
|
|
44
|
+
return default_value
|
|
45
|
+
else:
|
|
46
|
+
# Required variable not set
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"Required environment variable not set: {var_name}"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return ConfigFileLoader.ENV_VAR_PATTERN.sub(replacer, value)
|
|
52
|
+
|
|
53
|
+
elif isinstance(value, dict):
|
|
54
|
+
# Recursively process dictionary
|
|
55
|
+
return {
|
|
56
|
+
k: ConfigFileLoader._substitute_env_vars(v)
|
|
57
|
+
for k, v in value.items()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
elif isinstance(value, list):
|
|
61
|
+
# Recursively process list
|
|
62
|
+
return [ConfigFileLoader._substitute_env_vars(item) for item in value]
|
|
63
|
+
|
|
64
|
+
else:
|
|
65
|
+
# Return other types as-is (int, bool, None, etc.)
|
|
66
|
+
return value
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def _find_config_file(config_path: Optional[str] = None) -> Optional[Path]:
|
|
70
|
+
"""
|
|
71
|
+
Find configuration file.
|
|
72
|
+
|
|
73
|
+
Search order:
|
|
74
|
+
1. Explicit config_path parameter
|
|
75
|
+
2. KUBIYA_CONFIG_FILE environment variable
|
|
76
|
+
3. ./config.yaml (current directory)
|
|
77
|
+
4. /etc/kubiya/config.yaml (system-wide)
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
config_path: Optional explicit path to config file
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Path to config file or None if not found
|
|
84
|
+
"""
|
|
85
|
+
# 1. Explicit path
|
|
86
|
+
if config_path:
|
|
87
|
+
path = Path(config_path)
|
|
88
|
+
if path.exists():
|
|
89
|
+
return path
|
|
90
|
+
else:
|
|
91
|
+
logger.warning(
|
|
92
|
+
"config_file_not_found",
|
|
93
|
+
path=str(path),
|
|
94
|
+
message="Explicit config path does not exist"
|
|
95
|
+
)
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
# 2. Environment variable
|
|
99
|
+
env_path = os.getenv("KUBIYA_CONFIG_FILE")
|
|
100
|
+
if env_path:
|
|
101
|
+
path = Path(env_path)
|
|
102
|
+
if path.exists():
|
|
103
|
+
return path
|
|
104
|
+
else:
|
|
105
|
+
logger.warning(
|
|
106
|
+
"config_file_not_found",
|
|
107
|
+
path=str(path),
|
|
108
|
+
env_var="KUBIYA_CONFIG_FILE",
|
|
109
|
+
message="Config file from env var does not exist"
|
|
110
|
+
)
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
# 3. Current directory
|
|
114
|
+
cwd_config = Path("config.yaml")
|
|
115
|
+
if cwd_config.exists():
|
|
116
|
+
return cwd_config
|
|
117
|
+
|
|
118
|
+
# 4. System-wide config
|
|
119
|
+
system_config = Path("/etc/kubiya/config.yaml")
|
|
120
|
+
if system_config.exists():
|
|
121
|
+
return system_config
|
|
122
|
+
|
|
123
|
+
# No config file found
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def load_config(config_path: Optional[str] = None) -> Dict[str, Any]:
|
|
128
|
+
"""
|
|
129
|
+
Load configuration from YAML file with environment variable substitution.
|
|
130
|
+
|
|
131
|
+
Priority: Environment variables > YAML file > Defaults
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
config_path: Optional path to YAML config file
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Dict with configuration (empty dict if no config file found)
|
|
138
|
+
|
|
139
|
+
Raises:
|
|
140
|
+
ValueError: If required environment variable not set
|
|
141
|
+
yaml.YAMLError: If YAML syntax error
|
|
142
|
+
"""
|
|
143
|
+
# Find config file
|
|
144
|
+
config_file = ConfigFileLoader._find_config_file(config_path)
|
|
145
|
+
|
|
146
|
+
if not config_file:
|
|
147
|
+
logger.info(
|
|
148
|
+
"no_config_file_found",
|
|
149
|
+
message="No config file found, using environment variables only",
|
|
150
|
+
checked_paths=[
|
|
151
|
+
"config_path parameter",
|
|
152
|
+
"KUBIYA_CONFIG_FILE env var",
|
|
153
|
+
"./config.yaml",
|
|
154
|
+
"/etc/kubiya/config.yaml"
|
|
155
|
+
]
|
|
156
|
+
)
|
|
157
|
+
return {}
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
# Import YAML parser
|
|
161
|
+
try:
|
|
162
|
+
import yaml
|
|
163
|
+
except ImportError:
|
|
164
|
+
raise ImportError(
|
|
165
|
+
"PyYAML is required for YAML config files. "
|
|
166
|
+
"Install it with: pip install PyYAML"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Read and parse YAML
|
|
170
|
+
with open(config_file, "r", encoding="utf-8") as f:
|
|
171
|
+
raw_config = yaml.safe_load(f) or {}
|
|
172
|
+
|
|
173
|
+
# Substitute environment variables
|
|
174
|
+
config = ConfigFileLoader._substitute_env_vars(raw_config)
|
|
175
|
+
|
|
176
|
+
logger.info(
|
|
177
|
+
"config_file_loaded",
|
|
178
|
+
path=str(config_file),
|
|
179
|
+
keys=list(config.keys()) if isinstance(config, dict) else [],
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return config
|
|
183
|
+
|
|
184
|
+
except ImportError as e:
|
|
185
|
+
logger.error(
|
|
186
|
+
"config_loader_dependency_missing",
|
|
187
|
+
error=str(e),
|
|
188
|
+
path=str(config_file)
|
|
189
|
+
)
|
|
190
|
+
raise
|
|
191
|
+
|
|
192
|
+
except ValueError as e:
|
|
193
|
+
# Required env var not set
|
|
194
|
+
logger.error(
|
|
195
|
+
"config_env_var_required",
|
|
196
|
+
error=str(e),
|
|
197
|
+
path=str(config_file)
|
|
198
|
+
)
|
|
199
|
+
raise
|
|
200
|
+
|
|
201
|
+
except Exception as e:
|
|
202
|
+
logger.error(
|
|
203
|
+
"config_file_load_error",
|
|
204
|
+
error=str(e),
|
|
205
|
+
path=str(config_file),
|
|
206
|
+
error_type=type(e).__name__
|
|
207
|
+
)
|
|
208
|
+
raise
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# Convenience function
|
|
212
|
+
def load_config_file(config_path: Optional[str] = None) -> Dict[str, Any]:
|
|
213
|
+
"""
|
|
214
|
+
Load configuration from YAML file.
|
|
215
|
+
|
|
216
|
+
Convenience wrapper around ConfigFileLoader.load_config().
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
config_path: Optional path to YAML config file
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
Dict with configuration (empty dict if no config file found)
|
|
223
|
+
"""
|
|
224
|
+
return ConfigFileLoader.load_config(config_path)
|