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,382 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenTelemetry tracing configuration and utilities.
|
|
3
|
+
|
|
4
|
+
This module sets up the OpenTelemetry SDK with OTLP exporter support
|
|
5
|
+
and provides helper functions for creating spans with organizational context.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import structlog
|
|
9
|
+
from typing import Optional, Dict, Any
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
|
|
12
|
+
from opentelemetry import trace
|
|
13
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
14
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
15
|
+
from opentelemetry.sdk.resources import Resource, SERVICE_NAME, SERVICE_VERSION
|
|
16
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter as GRPCExporter
|
|
17
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter as HTTPExporter
|
|
18
|
+
from opentelemetry.sdk.trace.sampling import (
|
|
19
|
+
ParentBasedTraceIdRatio,
|
|
20
|
+
ParentBased,
|
|
21
|
+
ALWAYS_ON,
|
|
22
|
+
ALWAYS_OFF,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from control_plane_api.app.config import settings
|
|
26
|
+
|
|
27
|
+
logger = structlog.get_logger(__name__)
|
|
28
|
+
|
|
29
|
+
# Global tracer instance
|
|
30
|
+
_tracer: Optional[trace.Tracer] = None
|
|
31
|
+
_tracer_provider: Optional[TracerProvider] = None
|
|
32
|
+
_local_storage_processor = None # LocalStorageSpanProcessor instance
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _parse_resource_attributes() -> Dict[str, str]:
|
|
36
|
+
"""Parse OTEL_RESOURCE_ATTRIBUTES from environment variable.
|
|
37
|
+
|
|
38
|
+
Format: "key1=value1,key2=value2"
|
|
39
|
+
"""
|
|
40
|
+
attributes = {}
|
|
41
|
+
if settings.OTEL_RESOURCE_ATTRIBUTES:
|
|
42
|
+
for pair in settings.OTEL_RESOURCE_ATTRIBUTES.split(","):
|
|
43
|
+
if "=" in pair:
|
|
44
|
+
key, value = pair.split("=", 1)
|
|
45
|
+
attributes[key.strip()] = value.strip()
|
|
46
|
+
return attributes
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _create_sampler():
|
|
50
|
+
"""Create appropriate sampler based on configuration."""
|
|
51
|
+
sampler_name = settings.OTEL_TRACES_SAMPLER.lower()
|
|
52
|
+
|
|
53
|
+
if sampler_name == "always_off":
|
|
54
|
+
return ALWAYS_OFF
|
|
55
|
+
elif sampler_name == "always_on":
|
|
56
|
+
return ALWAYS_ON
|
|
57
|
+
elif sampler_name == "parentbased_always_on":
|
|
58
|
+
return ParentBased(root=ALWAYS_ON)
|
|
59
|
+
elif sampler_name == "parentbased_always_off":
|
|
60
|
+
return ParentBased(root=ALWAYS_OFF)
|
|
61
|
+
elif sampler_name == "parentbased_traceidratio":
|
|
62
|
+
ratio = settings.OTEL_TRACES_SAMPLER_ARG or 1.0
|
|
63
|
+
return ParentBased(root=ParentBasedTraceIdRatio(ratio))
|
|
64
|
+
elif sampler_name == "traceidratio":
|
|
65
|
+
ratio = settings.OTEL_TRACES_SAMPLER_ARG or 1.0
|
|
66
|
+
return ParentBasedTraceIdRatio(ratio)
|
|
67
|
+
else:
|
|
68
|
+
logger.warning(
|
|
69
|
+
"unknown_sampler_type",
|
|
70
|
+
sampler=sampler_name,
|
|
71
|
+
fallback="parentbased_always_on"
|
|
72
|
+
)
|
|
73
|
+
return ParentBased(root=ALWAYS_ON)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def setup_telemetry() -> None:
|
|
77
|
+
"""
|
|
78
|
+
Initialize OpenTelemetry SDK with OTLP exporter and/or local storage.
|
|
79
|
+
|
|
80
|
+
This should be called once at application startup.
|
|
81
|
+
If OTEL_ENABLED is False, tracing will be disabled (no-op tracer).
|
|
82
|
+
Local storage can work independently without external OTLP endpoint.
|
|
83
|
+
"""
|
|
84
|
+
global _tracer, _tracer_provider
|
|
85
|
+
|
|
86
|
+
if not settings.OTEL_ENABLED:
|
|
87
|
+
logger.info("otel_disabled", reason="OTEL_ENABLED=false")
|
|
88
|
+
# Set no-op tracer
|
|
89
|
+
trace.set_tracer_provider(trace.NoOpTracerProvider())
|
|
90
|
+
_tracer = trace.get_tracer(__name__)
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
# Check if we have any tracing destination (external OTLP or local storage)
|
|
94
|
+
has_otlp_endpoint = bool(settings.OTEL_EXPORTER_OTLP_ENDPOINT)
|
|
95
|
+
has_local_storage = getattr(settings, 'OTEL_LOCAL_STORAGE_ENABLED', True)
|
|
96
|
+
|
|
97
|
+
if not has_otlp_endpoint and not has_local_storage:
|
|
98
|
+
logger.warning(
|
|
99
|
+
"otel_no_destination_configured",
|
|
100
|
+
message="Neither OTLP endpoint nor local storage enabled, tracing disabled"
|
|
101
|
+
)
|
|
102
|
+
# Set no-op tracer
|
|
103
|
+
trace.set_tracer_provider(trace.NoOpTracerProvider())
|
|
104
|
+
_tracer = trace.get_tracer(__name__)
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
# Create resource with service information
|
|
109
|
+
resource_attributes = {
|
|
110
|
+
SERVICE_NAME: settings.OTEL_SERVICE_NAME,
|
|
111
|
+
SERVICE_VERSION: settings.api_version,
|
|
112
|
+
"deployment.environment": settings.environment,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Add custom resource attributes from config
|
|
116
|
+
resource_attributes.update(_parse_resource_attributes())
|
|
117
|
+
|
|
118
|
+
resource = Resource.create(resource_attributes)
|
|
119
|
+
|
|
120
|
+
# Create sampler
|
|
121
|
+
sampler = _create_sampler()
|
|
122
|
+
|
|
123
|
+
# Create tracer provider
|
|
124
|
+
_tracer_provider = TracerProvider(resource=resource, sampler=sampler)
|
|
125
|
+
|
|
126
|
+
# Only add OTLP exporter if endpoint is configured
|
|
127
|
+
if has_otlp_endpoint:
|
|
128
|
+
# Create appropriate exporter based on protocol
|
|
129
|
+
if settings.OTEL_EXPORTER_OTLP_PROTOCOL == "http":
|
|
130
|
+
# HTTP/protobuf exporter
|
|
131
|
+
endpoint = settings.OTEL_EXPORTER_OTLP_ENDPOINT
|
|
132
|
+
if not endpoint.endswith("/v1/traces"):
|
|
133
|
+
endpoint = f"{endpoint}/v1/traces"
|
|
134
|
+
exporter = HTTPExporter(endpoint=endpoint)
|
|
135
|
+
logger.info(
|
|
136
|
+
"otel_exporter_configured",
|
|
137
|
+
protocol="http",
|
|
138
|
+
endpoint=endpoint
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
# gRPC exporter (default)
|
|
142
|
+
exporter = GRPCExporter(
|
|
143
|
+
endpoint=settings.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
144
|
+
insecure=True # TODO: Configure TLS for production
|
|
145
|
+
)
|
|
146
|
+
logger.info(
|
|
147
|
+
"otel_exporter_configured",
|
|
148
|
+
protocol="grpc",
|
|
149
|
+
endpoint=settings.OTEL_EXPORTER_OTLP_ENDPOINT
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Add batch span processor with exporter
|
|
153
|
+
span_processor = BatchSpanProcessor(exporter)
|
|
154
|
+
_tracer_provider.add_span_processor(span_processor)
|
|
155
|
+
else:
|
|
156
|
+
logger.info(
|
|
157
|
+
"otel_exporter_skipped",
|
|
158
|
+
reason="No OTLP endpoint configured, using local storage only"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Add local storage processor for observability UI
|
|
162
|
+
global _local_storage_processor
|
|
163
|
+
if has_local_storage:
|
|
164
|
+
try:
|
|
165
|
+
from control_plane_api.app.observability.local_span_processor import (
|
|
166
|
+
setup_local_storage_processor,
|
|
167
|
+
)
|
|
168
|
+
_local_storage_processor = setup_local_storage_processor(
|
|
169
|
+
_tracer_provider,
|
|
170
|
+
)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
logger.warning(
|
|
173
|
+
"local_storage_processor_setup_failed",
|
|
174
|
+
error=str(e),
|
|
175
|
+
message="Continuing without local trace storage"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Set global tracer provider
|
|
179
|
+
trace.set_tracer_provider(_tracer_provider)
|
|
180
|
+
|
|
181
|
+
# Create tracer instance
|
|
182
|
+
_tracer = trace.get_tracer(
|
|
183
|
+
instrumenting_module_name="control_plane_api",
|
|
184
|
+
instrumenting_library_version=settings.api_version
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
logger.info(
|
|
188
|
+
"otel_initialized",
|
|
189
|
+
service_name=settings.OTEL_SERVICE_NAME,
|
|
190
|
+
otlp_endpoint=settings.OTEL_EXPORTER_OTLP_ENDPOINT or "none",
|
|
191
|
+
otlp_protocol=settings.OTEL_EXPORTER_OTLP_PROTOCOL if has_otlp_endpoint else "disabled",
|
|
192
|
+
local_storage=bool(_local_storage_processor),
|
|
193
|
+
sampler=settings.OTEL_TRACES_SAMPLER,
|
|
194
|
+
sampler_arg=settings.OTEL_TRACES_SAMPLER_ARG,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
except Exception as e:
|
|
198
|
+
logger.error(
|
|
199
|
+
"otel_initialization_failed",
|
|
200
|
+
error=str(e),
|
|
201
|
+
exc_info=True
|
|
202
|
+
)
|
|
203
|
+
# Fall back to no-op tracer on error
|
|
204
|
+
trace.set_tracer_provider(trace.NoOpTracerProvider())
|
|
205
|
+
_tracer = trace.get_tracer(__name__)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def get_tracer() -> trace.Tracer:
|
|
209
|
+
"""Get the global tracer instance."""
|
|
210
|
+
global _tracer
|
|
211
|
+
if _tracer is None:
|
|
212
|
+
# Return default tracer if not initialized
|
|
213
|
+
return trace.get_tracer(__name__)
|
|
214
|
+
return _tracer
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@contextmanager
|
|
218
|
+
def create_span_with_context(
|
|
219
|
+
name: str,
|
|
220
|
+
organization_id: Optional[str] = None,
|
|
221
|
+
user_id: Optional[str] = None,
|
|
222
|
+
user_email: Optional[str] = None,
|
|
223
|
+
user_name: Optional[str] = None,
|
|
224
|
+
user_avatar: Optional[str] = None,
|
|
225
|
+
execution_id: Optional[str] = None,
|
|
226
|
+
request_id: Optional[str] = None,
|
|
227
|
+
**attributes: Any,
|
|
228
|
+
):
|
|
229
|
+
"""
|
|
230
|
+
Create a span with standard organizational and user context.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
name: Span name (e.g., "streaming.phase_1_connect")
|
|
234
|
+
organization_id: Organization slug (e.g., "kubiya-ai")
|
|
235
|
+
user_id: User UUID
|
|
236
|
+
user_email: User email address
|
|
237
|
+
user_name: User display name
|
|
238
|
+
user_avatar: User avatar URL
|
|
239
|
+
execution_id: Execution UUID (if applicable)
|
|
240
|
+
request_id: Request ID from middleware
|
|
241
|
+
**attributes: Additional span attributes
|
|
242
|
+
|
|
243
|
+
Usage:
|
|
244
|
+
with create_span_with_context(
|
|
245
|
+
"worker.registration",
|
|
246
|
+
organization_id="kubiya-ai",
|
|
247
|
+
user_id="user-123",
|
|
248
|
+
user_email="user@example.com",
|
|
249
|
+
user_name="John Doe",
|
|
250
|
+
worker_queue_id="queue-456"
|
|
251
|
+
) as span:
|
|
252
|
+
# Do work
|
|
253
|
+
span.set_attribute("worker.id", worker_id)
|
|
254
|
+
"""
|
|
255
|
+
tracer = get_tracer()
|
|
256
|
+
|
|
257
|
+
with tracer.start_as_current_span(name) as span:
|
|
258
|
+
# Add standard organizational context
|
|
259
|
+
if organization_id:
|
|
260
|
+
span.set_attribute("organization.id", organization_id)
|
|
261
|
+
|
|
262
|
+
if user_id:
|
|
263
|
+
span.set_attribute("user.id", user_id)
|
|
264
|
+
|
|
265
|
+
if user_email:
|
|
266
|
+
span.set_attribute("user.email", user_email)
|
|
267
|
+
|
|
268
|
+
if user_name:
|
|
269
|
+
span.set_attribute("user.name", user_name)
|
|
270
|
+
|
|
271
|
+
if user_avatar:
|
|
272
|
+
span.set_attribute("user.avatar", user_avatar)
|
|
273
|
+
|
|
274
|
+
if execution_id:
|
|
275
|
+
span.set_attribute("execution.id", execution_id)
|
|
276
|
+
|
|
277
|
+
if request_id:
|
|
278
|
+
span.set_attribute("request.id", request_id)
|
|
279
|
+
|
|
280
|
+
# Add custom attributes
|
|
281
|
+
for key, value in attributes.items():
|
|
282
|
+
if value is not None:
|
|
283
|
+
# Convert value to string for non-primitive types
|
|
284
|
+
if isinstance(value, (str, int, float, bool)):
|
|
285
|
+
span.set_attribute(key, value)
|
|
286
|
+
else:
|
|
287
|
+
span.set_attribute(key, str(value))
|
|
288
|
+
|
|
289
|
+
yield span
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def get_current_trace_id() -> Optional[str]:
|
|
293
|
+
"""
|
|
294
|
+
Get the current trace ID as a hex string.
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
Trace ID in format: "4bf92f3577b34da6a3ce929d0e0e4736"
|
|
298
|
+
None if no active span
|
|
299
|
+
"""
|
|
300
|
+
span = trace.get_current_span()
|
|
301
|
+
if span and span.is_recording():
|
|
302
|
+
trace_id = span.get_span_context().trace_id
|
|
303
|
+
return format(trace_id, '032x')
|
|
304
|
+
return None
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def get_current_span_id() -> Optional[str]:
|
|
308
|
+
"""
|
|
309
|
+
Get the current span ID as a hex string.
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
16-character hex string of the 64-bit span ID, or None if no active span
|
|
313
|
+
"""
|
|
314
|
+
span = trace.get_current_span()
|
|
315
|
+
if span and span.is_recording():
|
|
316
|
+
span_id = span.get_span_context().span_id
|
|
317
|
+
return format(span_id, '016x')
|
|
318
|
+
return None
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def add_span_event(name: str, attributes: Optional[Dict[str, Any]] = None) -> None:
|
|
322
|
+
"""
|
|
323
|
+
Add an event (log) to the current span for better trace visibility.
|
|
324
|
+
|
|
325
|
+
This makes logs visible in the Jaeger UI as span events.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
name: Event name (e.g., "Database query started", "LLM response received")
|
|
329
|
+
attributes: Optional key-value pairs with event details
|
|
330
|
+
|
|
331
|
+
Example:
|
|
332
|
+
add_span_event("Agent execution started", {"agent_id": "abc123", "prompt": "Deploy app"})
|
|
333
|
+
# ... do work ...
|
|
334
|
+
add_span_event("Agent execution completed", {"status": "success", "duration_ms": 1234})
|
|
335
|
+
"""
|
|
336
|
+
span = trace.get_current_span()
|
|
337
|
+
if span and span.is_recording():
|
|
338
|
+
event_attrs = attributes or {}
|
|
339
|
+
span.add_event(name, event_attrs)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def add_span_error(error: Exception, attributes: Optional[Dict[str, Any]] = None) -> None:
|
|
343
|
+
"""
|
|
344
|
+
Record an error in the current span with full context.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
error: The exception that occurred
|
|
348
|
+
attributes: Optional additional context about the error
|
|
349
|
+
|
|
350
|
+
Example:
|
|
351
|
+
try:
|
|
352
|
+
risky_operation()
|
|
353
|
+
except Exception as e:
|
|
354
|
+
add_span_error(e, {"operation": "database_write", "table": "users"})
|
|
355
|
+
raise
|
|
356
|
+
"""
|
|
357
|
+
span = trace.get_current_span()
|
|
358
|
+
if span and span.is_recording():
|
|
359
|
+
from opentelemetry.trace import StatusCode
|
|
360
|
+
|
|
361
|
+
span.set_status(StatusCode.ERROR, str(error))
|
|
362
|
+
span.record_exception(error)
|
|
363
|
+
|
|
364
|
+
if attributes:
|
|
365
|
+
for key, value in attributes.items():
|
|
366
|
+
span.set_attribute(f"error.{key}", str(value))
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def shutdown_telemetry() -> None:
|
|
370
|
+
"""
|
|
371
|
+
Shutdown the OpenTelemetry SDK and flush remaining spans.
|
|
372
|
+
|
|
373
|
+
This should be called during application shutdown.
|
|
374
|
+
"""
|
|
375
|
+
global _tracer_provider
|
|
376
|
+
|
|
377
|
+
if _tracer_provider:
|
|
378
|
+
try:
|
|
379
|
+
_tracer_provider.shutdown()
|
|
380
|
+
logger.info("otel_shutdown_complete")
|
|
381
|
+
except Exception as e:
|
|
382
|
+
logger.error("otel_shutdown_failed", error=str(e), exc_info=True)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Policy Modules for Agent Control Plane
|
|
2
|
+
|
|
3
|
+
This directory contains pre-built OPA (Open Policy Agent) policy modules written in Rego for common agent control plane operations.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Policies are stored and evaluated in the OPA Watchdog Enforcer Service. These modules provide templates and examples for:
|
|
8
|
+
|
|
9
|
+
- **Execution Policies**: Control when and how agents can execute
|
|
10
|
+
- **Resource Policies**: Limit resource usage and access
|
|
11
|
+
- **Time-based Policies**: Business hours and rate limiting
|
|
12
|
+
- **Tool Enforcement Policies**: Real-time validation of tool executions (NEW)
|
|
13
|
+
- **Tool Policies**: Control which tools agents can use
|
|
14
|
+
- **Team Policies**: Collaboration and approval workflows
|
|
15
|
+
|
|
16
|
+
### Tool Enforcement Policies (NEW)
|
|
17
|
+
|
|
18
|
+
The `tool_enforcement/` directory contains policies for **real-time tool call enforcement** during agent execution. These policies are evaluated before each tool execution and can block or allow tools based on:
|
|
19
|
+
|
|
20
|
+
- User roles and permissions
|
|
21
|
+
- Tool risk level (critical/high/medium/low)
|
|
22
|
+
- Environment (production/staging/dev)
|
|
23
|
+
- Time of day (business hours)
|
|
24
|
+
- Tool source (MCP/builtin/skill)
|
|
25
|
+
- Command patterns (dangerous bash commands)
|
|
26
|
+
|
|
27
|
+
See the [Tool Enforcement Guide](../../../docs/TOOL_ENFORCEMENT.md) for detailed documentation.
|
|
28
|
+
|
|
29
|
+
## Policy Structure
|
|
30
|
+
|
|
31
|
+
All policies follow this structure:
|
|
32
|
+
|
|
33
|
+
```rego
|
|
34
|
+
package <policy_name>
|
|
35
|
+
|
|
36
|
+
# Default decision (deny by default)
|
|
37
|
+
default allow = false
|
|
38
|
+
|
|
39
|
+
# Rules that grant permissions
|
|
40
|
+
allow {
|
|
41
|
+
# conditions
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Violations that explain why requests are denied
|
|
45
|
+
violations[msg] {
|
|
46
|
+
# condition
|
|
47
|
+
msg := "Explanation"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Policy Priority and Inheritance
|
|
52
|
+
|
|
53
|
+
Policies are associated with entities (agents, teams, environments) with automatic inheritance:
|
|
54
|
+
|
|
55
|
+
1. **Environment** policies (priority: 300) - apply to all agents/teams in the environment
|
|
56
|
+
2. **Team** policies (priority: 200) - apply to all agents in the team
|
|
57
|
+
3. **Agent** policies (priority: 100) - apply to specific agent
|
|
58
|
+
|
|
59
|
+
When the same policy is defined at multiple levels, **higher priority wins**.
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
### 1. Create a Policy
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
curl -X POST https://your-control-plane.com/api/v1/policies \
|
|
67
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
68
|
+
-H "Content-Type: application/json" \
|
|
69
|
+
-d '{
|
|
70
|
+
"name": "business-hours-only",
|
|
71
|
+
"policy_content": "<rego_policy>",
|
|
72
|
+
"description": "Allow executions only during business hours",
|
|
73
|
+
"enabled": true,
|
|
74
|
+
"tags": ["time", "compliance"]
|
|
75
|
+
}'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 2. Associate with Entity
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
curl -X POST https://your-control-plane.com/api/v1/policies/associations \
|
|
82
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
83
|
+
-H "Content-Type: application/json" \
|
|
84
|
+
-d '{
|
|
85
|
+
"policy_id": "<policy_uuid>",
|
|
86
|
+
"policy_name": "business-hours-only",
|
|
87
|
+
"entity_type": "environment",
|
|
88
|
+
"entity_id": "<environment_uuid>",
|
|
89
|
+
"enabled": true
|
|
90
|
+
}'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Evaluate Policy
|
|
94
|
+
|
|
95
|
+
Policies are automatically evaluated during agent execution. You can also test manually:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
curl -X POST https://your-control-plane.com/api/v1/policies/evaluate/agent/<agent_id> \
|
|
99
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
100
|
+
-H "Content-Type: application/json" \
|
|
101
|
+
-d '{
|
|
102
|
+
"input_data": {
|
|
103
|
+
"action": "execute",
|
|
104
|
+
"user": "alice@company.com",
|
|
105
|
+
"time": "2025-01-15T14:30:00Z"
|
|
106
|
+
}
|
|
107
|
+
}'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Available Policy Modules
|
|
111
|
+
|
|
112
|
+
### Tool Enforcement Policies (`tool_enforcement/`)
|
|
113
|
+
|
|
114
|
+
Real-time tool call validation policies:
|
|
115
|
+
|
|
116
|
+
- **`role_based_tool_access.rego`** - Restrict command execution tools to admin/devops roles
|
|
117
|
+
- **`production_safeguards.rego`** - Block critical/high-risk tools in production environment
|
|
118
|
+
- **`bash_command_validation.rego`** - Block dangerous bash patterns (rm -rf, dd, mkfs, etc.)
|
|
119
|
+
- **`business_hours_enforcement.rego`** - Restrict high-risk tools to business hours (9 AM - 6 PM UTC, Mon-Fri)
|
|
120
|
+
- **`mcp_tool_allowlist.rego`** - Whitelist approved MCP tools
|
|
121
|
+
|
|
122
|
+
All tool enforcement policies use package `kubiya.tool_enforcement` and evaluate against structured tool execution input. See [Tool Enforcement Guide](../../../docs/TOOL_ENFORCEMENT.md) for input schema and examples.
|
|
123
|
+
|
|
124
|
+
### General Policy Modules
|
|
125
|
+
|
|
126
|
+
See individual `.rego` files for detailed policies:
|
|
127
|
+
|
|
128
|
+
- `business_hours.rego` - Restrict executions to business hours
|
|
129
|
+
- `approved_users.rego` - Require user approval list
|
|
130
|
+
- `rate_limiting.rego` - Limit execution frequency
|
|
131
|
+
- `resource_limits.rego` - Enforce resource quotas
|
|
132
|
+
- `tool_restrictions.rego` - Control tool usage
|
|
133
|
+
- `approval_workflow.rego` - Require approvals for sensitive actions
|
|
134
|
+
- `environment_restrictions.rego` - Restrict access to environments
|
|
135
|
+
|
|
136
|
+
## Policy Development Tips
|
|
137
|
+
|
|
138
|
+
1. **Test policies locally** using OPA CLI before deploying
|
|
139
|
+
2. **Start with deny-by-default** for security
|
|
140
|
+
3. **Use clear violation messages** for debugging
|
|
141
|
+
4. **Document assumptions** in policy comments
|
|
142
|
+
5. **Version policies** using tags or metadata
|
|
143
|
+
6. **Test edge cases** thoroughly
|
|
144
|
+
|
|
145
|
+
## References
|
|
146
|
+
|
|
147
|
+
- [OPA Documentation](https://www.openpolicyagent.org/docs/latest/)
|
|
148
|
+
- [Rego Language Reference](https://www.openpolicyagent.org/docs/latest/policy-reference/)
|
|
149
|
+
- [OPA Watchdog Enforcer API](https://enforcer-psi.vercel.app/api/docs)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Approved Users Policy
|
|
2
|
+
# Only allows executions from a whitelist of approved users
|
|
3
|
+
|
|
4
|
+
package approved_users
|
|
5
|
+
|
|
6
|
+
import future.keywords.if
|
|
7
|
+
import future.keywords.in
|
|
8
|
+
|
|
9
|
+
# Default deny
|
|
10
|
+
default allow = false
|
|
11
|
+
|
|
12
|
+
# List of approved users (emails)
|
|
13
|
+
# This can be customized per organization or pulled from metadata
|
|
14
|
+
approved_user_list := {
|
|
15
|
+
"admin@company.com",
|
|
16
|
+
"devops@company.com",
|
|
17
|
+
"alice@company.com",
|
|
18
|
+
"bob@company.com"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Allow if user is in the approved list
|
|
22
|
+
allow if {
|
|
23
|
+
input.user in approved_user_list
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Also allow if user email domain is approved
|
|
27
|
+
allow if {
|
|
28
|
+
user_email := input.user
|
|
29
|
+
contains(user_email, "@")
|
|
30
|
+
domain := split(user_email, "@")[1]
|
|
31
|
+
domain in approved_domains
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Approved email domains
|
|
35
|
+
approved_domains := {
|
|
36
|
+
"company.com",
|
|
37
|
+
"trusted-partner.com"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Violations
|
|
41
|
+
violations[msg] if {
|
|
42
|
+
not input.user in approved_user_list
|
|
43
|
+
user_email := input.user
|
|
44
|
+
contains(user_email, "@")
|
|
45
|
+
domain := split(user_email, "@")[1]
|
|
46
|
+
not domain in approved_domains
|
|
47
|
+
msg := sprintf("User '%v' is not in the approved user list or approved domain", [input.user])
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
violations[msg] if {
|
|
51
|
+
not input.user
|
|
52
|
+
msg := "No user specified in the request"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Metadata
|
|
56
|
+
metadata := {
|
|
57
|
+
"name": "approved-users-only",
|
|
58
|
+
"description": "Only allow executions from approved users or domains",
|
|
59
|
+
"version": "1.0.0",
|
|
60
|
+
"author": "Kubiya",
|
|
61
|
+
"tags": ["security", "access-control", "users"]
|
|
62
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Business Hours Policy
|
|
2
|
+
# Restricts agent executions to business hours (9 AM - 5 PM, Monday-Friday)
|
|
3
|
+
|
|
4
|
+
package business_hours
|
|
5
|
+
|
|
6
|
+
import future.keywords.if
|
|
7
|
+
import future.keywords.in
|
|
8
|
+
|
|
9
|
+
# Default deny
|
|
10
|
+
default allow = false
|
|
11
|
+
|
|
12
|
+
# Allow executions during business hours
|
|
13
|
+
allow if {
|
|
14
|
+
is_business_hours
|
|
15
|
+
not is_weekend
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Check if current time is within business hours (9 AM - 5 PM)
|
|
19
|
+
is_business_hours if {
|
|
20
|
+
time_hour := time.parse_rfc3339_ns(input.time)
|
|
21
|
+
hour := time.clock(time_hour)[0]
|
|
22
|
+
hour >= 9
|
|
23
|
+
hour < 17
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Check if current day is a weekend
|
|
27
|
+
is_weekend if {
|
|
28
|
+
time_day := time.parse_rfc3339_ns(input.time)
|
|
29
|
+
weekday := time.weekday(time_day)
|
|
30
|
+
weekday in ["Saturday", "Sunday"]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Violations
|
|
34
|
+
violations[msg] if {
|
|
35
|
+
not is_business_hours
|
|
36
|
+
msg := sprintf("Execution requested outside business hours (9 AM - 5 PM). Current time: %v", [input.time])
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
violations[msg] if {
|
|
40
|
+
is_weekend
|
|
41
|
+
msg := sprintf("Execution requested on weekend. Current day: %v", [time.weekday(time.parse_rfc3339_ns(input.time))])
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Metadata
|
|
45
|
+
metadata := {
|
|
46
|
+
"name": "business-hours-only",
|
|
47
|
+
"description": "Restrict agent executions to business hours (9 AM - 5 PM, Monday-Friday)",
|
|
48
|
+
"version": "1.0.0",
|
|
49
|
+
"author": "Kubiya",
|
|
50
|
+
"tags": ["time", "compliance", "business-hours"]
|
|
51
|
+
}
|