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,181 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Skill Context Enhancement for System Prompts.
|
|
3
|
+
|
|
4
|
+
This enhancement extracts context information from skill configurations
|
|
5
|
+
and injects it into the system prompt to provide agents with usage guidelines
|
|
6
|
+
and environment awareness.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Optional, List, Dict, Any
|
|
10
|
+
import structlog
|
|
11
|
+
|
|
12
|
+
from control_plane_api.worker.services.system_prompt_enhancement import (
|
|
13
|
+
SystemPromptEnhancement,
|
|
14
|
+
RuntimeType,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
logger = structlog.get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SkillContextEnhancement(SystemPromptEnhancement):
|
|
21
|
+
"""
|
|
22
|
+
Inject skill context (usage guidelines, environment info) into system prompt.
|
|
23
|
+
|
|
24
|
+
This enhancement reads skill configurations passed via RuntimeExecutionContext
|
|
25
|
+
and generates formatted context sections that help the agent understand:
|
|
26
|
+
- How to use specific skills effectively
|
|
27
|
+
- Environment-specific information
|
|
28
|
+
- Custom shell configurations
|
|
29
|
+
|
|
30
|
+
The enhancement is designed to work with skill configurations that include:
|
|
31
|
+
- usage_guidelines: Optional[str] - Instructions for using the skill
|
|
32
|
+
- environment_context: Optional[str] - Environment-specific information
|
|
33
|
+
- shell_binary: Optional[str] - Custom shell binary path
|
|
34
|
+
- shell_args: Optional[List[str]] - Shell arguments
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, skill_configs: Optional[List[Dict[str, Any]]] = None):
|
|
38
|
+
"""
|
|
39
|
+
Initialize skill context enhancement.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
skill_configs: List of skill configuration dictionaries.
|
|
43
|
+
If None, no context will be injected.
|
|
44
|
+
"""
|
|
45
|
+
# Apply to all runtimes
|
|
46
|
+
super().__init__(runtime_types=[RuntimeType.ALL])
|
|
47
|
+
self.skill_configs = skill_configs or []
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def name(self) -> str:
|
|
51
|
+
return "skill_context"
|
|
52
|
+
|
|
53
|
+
def enhance(self, base_prompt: Optional[str]) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Enhance system prompt with skill context information.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
base_prompt: The base system prompt
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Enhanced prompt with skill context sections
|
|
62
|
+
"""
|
|
63
|
+
if not self.skill_configs:
|
|
64
|
+
# No skills configured - return base prompt unchanged
|
|
65
|
+
return base_prompt or ""
|
|
66
|
+
|
|
67
|
+
# Extract skills with context information
|
|
68
|
+
skills_with_context = [
|
|
69
|
+
skill for skill in self.skill_configs
|
|
70
|
+
if self._has_context_fields(skill)
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
if not skills_with_context:
|
|
74
|
+
# No skills have context fields - return base prompt unchanged
|
|
75
|
+
logger.debug(
|
|
76
|
+
"skill_context_enhancement_skipped",
|
|
77
|
+
reason="no_skills_with_context_fields",
|
|
78
|
+
total_skills=len(self.skill_configs),
|
|
79
|
+
)
|
|
80
|
+
return base_prompt or ""
|
|
81
|
+
|
|
82
|
+
# Build context sections
|
|
83
|
+
context_parts = []
|
|
84
|
+
context_parts.append("") # Blank line before section
|
|
85
|
+
context_parts.append("---")
|
|
86
|
+
context_parts.append("")
|
|
87
|
+
context_parts.append("# Skill Context & Usage Guidelines")
|
|
88
|
+
context_parts.append("")
|
|
89
|
+
context_parts.append(
|
|
90
|
+
"The following skills have been configured with specific usage "
|
|
91
|
+
"guidelines and environment information to help you use them effectively:"
|
|
92
|
+
)
|
|
93
|
+
context_parts.append("")
|
|
94
|
+
|
|
95
|
+
for skill in skills_with_context:
|
|
96
|
+
try:
|
|
97
|
+
skill_name = skill.get("name", "Unknown Skill")
|
|
98
|
+
skill_type = skill.get("type", "unknown")
|
|
99
|
+
config = skill.get("configuration", {})
|
|
100
|
+
|
|
101
|
+
# Add skill header
|
|
102
|
+
context_parts.append(f"## {skill_name}")
|
|
103
|
+
context_parts.append("")
|
|
104
|
+
|
|
105
|
+
# Add usage guidelines if present
|
|
106
|
+
usage_guidelines = config.get("usage_guidelines", "").strip()
|
|
107
|
+
if usage_guidelines:
|
|
108
|
+
context_parts.append("**Usage Guidelines:**")
|
|
109
|
+
context_parts.append("")
|
|
110
|
+
# Handle multi-line guidelines
|
|
111
|
+
for line in usage_guidelines.split("\n"):
|
|
112
|
+
context_parts.append(line)
|
|
113
|
+
context_parts.append("")
|
|
114
|
+
|
|
115
|
+
# Add environment context if present
|
|
116
|
+
environment_context = config.get("environment_context", "").strip()
|
|
117
|
+
if environment_context:
|
|
118
|
+
context_parts.append("**Environment Context:**")
|
|
119
|
+
context_parts.append("")
|
|
120
|
+
for line in environment_context.split("\n"):
|
|
121
|
+
context_parts.append(line)
|
|
122
|
+
context_parts.append("")
|
|
123
|
+
|
|
124
|
+
# Add shell configuration if present (for shell skills)
|
|
125
|
+
if skill_type in ["shell", "SHELL"]:
|
|
126
|
+
shell_binary = config.get("shell_binary")
|
|
127
|
+
shell_args = config.get("shell_args")
|
|
128
|
+
|
|
129
|
+
if shell_binary or shell_args:
|
|
130
|
+
context_parts.append("**Shell Configuration:**")
|
|
131
|
+
context_parts.append("")
|
|
132
|
+
if shell_binary:
|
|
133
|
+
context_parts.append(f"- Binary: `{shell_binary}`")
|
|
134
|
+
if shell_args:
|
|
135
|
+
args_str = " ".join(shell_args)
|
|
136
|
+
context_parts.append(f"- Arguments: `{args_str}`")
|
|
137
|
+
context_parts.append("")
|
|
138
|
+
except Exception as e:
|
|
139
|
+
logger.warning(
|
|
140
|
+
"skill_context_enhancement_skipped_malformed_skill",
|
|
141
|
+
error=str(e),
|
|
142
|
+
skill=skill,
|
|
143
|
+
)
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
context_parts.append("---")
|
|
147
|
+
context_parts.append("")
|
|
148
|
+
|
|
149
|
+
enhancement_text = "\n".join(context_parts)
|
|
150
|
+
|
|
151
|
+
# Log the enhancement
|
|
152
|
+
logger.info(
|
|
153
|
+
"skill_context_enhancement_applied",
|
|
154
|
+
skills_with_context=len(skills_with_context),
|
|
155
|
+
total_skills=len(self.skill_configs),
|
|
156
|
+
enhancement_size=len(enhancement_text),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Append to base prompt
|
|
160
|
+
if base_prompt:
|
|
161
|
+
return base_prompt + "\n\n" + enhancement_text
|
|
162
|
+
else:
|
|
163
|
+
return enhancement_text.lstrip()
|
|
164
|
+
|
|
165
|
+
def _has_context_fields(self, skill: Dict[str, Any]) -> bool:
|
|
166
|
+
"""
|
|
167
|
+
Check if a skill configuration has any context fields.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
skill: Skill configuration dictionary
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
True if skill has usage_guidelines, environment_context, or shell config
|
|
174
|
+
"""
|
|
175
|
+
config = skill.get("configuration", {})
|
|
176
|
+
return bool(
|
|
177
|
+
config.get("usage_guidelines", "").strip()
|
|
178
|
+
or config.get("environment_context", "").strip()
|
|
179
|
+
or config.get("shell_binary")
|
|
180
|
+
or config.get("shell_args")
|
|
181
|
+
)
|
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Skill Factory - Dynamic skill loading with zero hardcoding
|
|
3
|
+
|
|
4
|
+
This factory discovers and instantiates skills dynamically from multiple sources
|
|
5
|
+
without any hardcoded if/elif chains. Works across all runtimes (agno, claude_code, etc.).
|
|
6
|
+
"""
|
|
7
|
+
from typing import Optional, Any, List
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import structlog
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from control_plane_api.worker.skills import (
|
|
13
|
+
SkillRegistry,
|
|
14
|
+
skill_registry,
|
|
15
|
+
FilesystemSkillLoader,
|
|
16
|
+
LoadedSkill,
|
|
17
|
+
)
|
|
18
|
+
from control_plane_api.worker.utils.tool_validation import (
|
|
19
|
+
validate_and_sanitize_tools,
|
|
20
|
+
is_valid_tool_name,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
logger = structlog.get_logger()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SkillFactory:
|
|
27
|
+
"""
|
|
28
|
+
Dynamic skill factory with zero hardcoding.
|
|
29
|
+
|
|
30
|
+
Discovers and instantiates skills from multiple sources automatically.
|
|
31
|
+
No hardcoded if/elif chains required.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, runtime_type: str = "agno"):
|
|
35
|
+
"""
|
|
36
|
+
Initialize the skill factory.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
runtime_type: Runtime type (e.g., "agno", "claude_code")
|
|
40
|
+
"""
|
|
41
|
+
self.runtime_type = runtime_type
|
|
42
|
+
self.registry: SkillRegistry = skill_registry
|
|
43
|
+
self.loaders = []
|
|
44
|
+
self._initialized = False
|
|
45
|
+
|
|
46
|
+
logger.info(
|
|
47
|
+
"skill_factory_initialized",
|
|
48
|
+
runtime_type=runtime_type,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def _validate_skill_tools(self, skill_instance: Any, skill_name: str) -> Optional[Any]:
|
|
52
|
+
"""
|
|
53
|
+
Validate and sanitize tool names from a skill instance.
|
|
54
|
+
|
|
55
|
+
This ensures ALL tools from ANY source meet universal LLM provider requirements.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
skill_instance: The skill toolkit instance
|
|
59
|
+
skill_name: Name of the skill for logging
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
The skill instance with validated tools, or None if validation fails critically
|
|
63
|
+
"""
|
|
64
|
+
# Try to extract tools from the skill instance
|
|
65
|
+
tools = []
|
|
66
|
+
|
|
67
|
+
# Handle Agno Toolkit objects
|
|
68
|
+
if hasattr(skill_instance, 'tools'):
|
|
69
|
+
tools = skill_instance.tools
|
|
70
|
+
# Handle dict format (builtin skills)
|
|
71
|
+
elif isinstance(skill_instance, dict) and 'tools' in skill_instance:
|
|
72
|
+
tools = skill_instance['tools']
|
|
73
|
+
# Handle iterable of tools
|
|
74
|
+
elif hasattr(skill_instance, '__iter__') and not isinstance(skill_instance, (str, dict)):
|
|
75
|
+
try:
|
|
76
|
+
tools = list(skill_instance)
|
|
77
|
+
except:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
if not tools:
|
|
81
|
+
# No tools to validate or can't extract them
|
|
82
|
+
return skill_instance
|
|
83
|
+
|
|
84
|
+
# Validate and sanitize tool names
|
|
85
|
+
def get_tool_name(tool):
|
|
86
|
+
"""Extract tool name from various tool formats."""
|
|
87
|
+
if hasattr(tool, 'name'):
|
|
88
|
+
return tool.name
|
|
89
|
+
elif isinstance(tool, dict):
|
|
90
|
+
return tool.get('name', tool.get('function', {}).get('name', str(tool)))
|
|
91
|
+
elif hasattr(tool, '__name__'):
|
|
92
|
+
return tool.__name__
|
|
93
|
+
return str(tool)
|
|
94
|
+
|
|
95
|
+
validated_tools, validation_report = validate_and_sanitize_tools(
|
|
96
|
+
tools,
|
|
97
|
+
tool_name_getter=get_tool_name,
|
|
98
|
+
auto_fix=True,
|
|
99
|
+
provider_context=self.runtime_type
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Log validation results
|
|
103
|
+
sanitized_count = sum(1 for r in validation_report if r['action'] == 'sanitized')
|
|
104
|
+
filtered_count = sum(1 for r in validation_report if r['action'] == 'filtered')
|
|
105
|
+
|
|
106
|
+
if sanitized_count > 0:
|
|
107
|
+
logger.warning(
|
|
108
|
+
"skill_tools_sanitized",
|
|
109
|
+
skill=skill_name,
|
|
110
|
+
runtime=self.runtime_type,
|
|
111
|
+
sanitized_count=sanitized_count,
|
|
112
|
+
total_tools=len(tools),
|
|
113
|
+
details=[r for r in validation_report if r['action'] == 'sanitized']
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if filtered_count > 0:
|
|
117
|
+
logger.error(
|
|
118
|
+
"skill_tools_filtered",
|
|
119
|
+
skill=skill_name,
|
|
120
|
+
runtime=self.runtime_type,
|
|
121
|
+
filtered_count=filtered_count,
|
|
122
|
+
total_tools=len(tools),
|
|
123
|
+
details=[r for r in validation_report if r['action'] == 'filtered']
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Update the skill instance with validated tools
|
|
127
|
+
if hasattr(skill_instance, 'tools'):
|
|
128
|
+
skill_instance.tools = validated_tools
|
|
129
|
+
elif isinstance(skill_instance, dict) and 'tools' in skill_instance:
|
|
130
|
+
skill_instance['tools'] = validated_tools
|
|
131
|
+
|
|
132
|
+
return skill_instance
|
|
133
|
+
|
|
134
|
+
def initialize(self):
|
|
135
|
+
"""
|
|
136
|
+
Initialize the factory by discovering skills from all sources.
|
|
137
|
+
|
|
138
|
+
Call this once during worker startup.
|
|
139
|
+
"""
|
|
140
|
+
if self._initialized:
|
|
141
|
+
logger.debug("skill_factory_already_initialized")
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
logger.info("skill_factory_initializing")
|
|
145
|
+
|
|
146
|
+
# Setup loaders
|
|
147
|
+
self._setup_loaders()
|
|
148
|
+
|
|
149
|
+
# Discover skills
|
|
150
|
+
self._discover_skills()
|
|
151
|
+
|
|
152
|
+
self._initialized = True
|
|
153
|
+
|
|
154
|
+
# Log statistics
|
|
155
|
+
stats = self.registry.get_stats()
|
|
156
|
+
logger.info(
|
|
157
|
+
"skill_factory_initialized",
|
|
158
|
+
total_skills=stats["total_skills"],
|
|
159
|
+
by_source=stats["skills_by_source"],
|
|
160
|
+
by_type=stats["skills_by_type"],
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def _setup_loaders(self):
|
|
164
|
+
"""Setup skill loaders from different sources."""
|
|
165
|
+
# 1. Filesystem loader (user skills)
|
|
166
|
+
search_paths = []
|
|
167
|
+
|
|
168
|
+
# Project skills (.kubiya/skills in current working directory)
|
|
169
|
+
project_skills = Path.cwd() / ".kubiya/skills"
|
|
170
|
+
if project_skills.exists():
|
|
171
|
+
search_paths.append(project_skills)
|
|
172
|
+
|
|
173
|
+
# User global skills (~/.kubiya/skills)
|
|
174
|
+
user_skills = Path.home() / ".kubiya/skills"
|
|
175
|
+
if user_skills.exists():
|
|
176
|
+
search_paths.append(user_skills)
|
|
177
|
+
|
|
178
|
+
# Built-in skills (in package directory)
|
|
179
|
+
builtin_skills = Path(__file__).parent.parent / "skills" / "builtin"
|
|
180
|
+
if builtin_skills.exists():
|
|
181
|
+
search_paths.append(builtin_skills)
|
|
182
|
+
|
|
183
|
+
if search_paths:
|
|
184
|
+
fs_loader = FilesystemSkillLoader(search_paths)
|
|
185
|
+
self.loaders.append(fs_loader)
|
|
186
|
+
logger.info("filesystem_loader_configured", paths=[str(p) for p in search_paths])
|
|
187
|
+
|
|
188
|
+
# TODO: Add API loader for Control Plane skills
|
|
189
|
+
# TODO: Add package loader for pip-installed skills
|
|
190
|
+
# TODO: Add git loader for remote skills
|
|
191
|
+
|
|
192
|
+
def _discover_skills(self):
|
|
193
|
+
"""Discover skills from all loaders."""
|
|
194
|
+
for loader in self.loaders:
|
|
195
|
+
try:
|
|
196
|
+
skills = loader.discover()
|
|
197
|
+
|
|
198
|
+
for skill in skills:
|
|
199
|
+
# Check dependencies
|
|
200
|
+
missing = self.registry.resolve_dependencies(skill)
|
|
201
|
+
if missing:
|
|
202
|
+
logger.warning(
|
|
203
|
+
"skill_missing_dependencies",
|
|
204
|
+
skill=skill.name,
|
|
205
|
+
missing=missing,
|
|
206
|
+
)
|
|
207
|
+
# Register anyway - could still be usable
|
|
208
|
+
|
|
209
|
+
# Register
|
|
210
|
+
self.registry.register(skill)
|
|
211
|
+
|
|
212
|
+
except Exception as e:
|
|
213
|
+
logger.error(
|
|
214
|
+
"skill_discovery_failed",
|
|
215
|
+
loader=loader.__class__.__name__,
|
|
216
|
+
error=str(e),
|
|
217
|
+
exc_info=True,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
def create_skill(self, skill_data: dict) -> Optional[Any]:
|
|
221
|
+
"""
|
|
222
|
+
Create a skill toolkit from configuration.
|
|
223
|
+
|
|
224
|
+
No hardcoded mappings - uses registry for discovery.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
skill_data: Skill config from Control Plane:
|
|
228
|
+
- name: Skill name (e.g., "slack-notifier")
|
|
229
|
+
- type: Skill type (e.g., "shell", "file_system", "custom")
|
|
230
|
+
- configuration: Dict with skill-specific config
|
|
231
|
+
- enabled: Whether skill is enabled
|
|
232
|
+
- execution_id: Optional execution ID for streaming
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Instantiated skill toolkit or None
|
|
236
|
+
"""
|
|
237
|
+
# Ensure factory is initialized
|
|
238
|
+
if not self._initialized:
|
|
239
|
+
self.initialize()
|
|
240
|
+
|
|
241
|
+
if not skill_data.get("enabled", True):
|
|
242
|
+
logger.info("skill_disabled", name=skill_data.get("name"))
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
skill_name = skill_data.get("name")
|
|
246
|
+
skill_type = skill_data.get("type", "custom")
|
|
247
|
+
config = skill_data.get("configuration", {})
|
|
248
|
+
execution_id = skill_data.get("execution_id")
|
|
249
|
+
|
|
250
|
+
# Try to find skill by name first
|
|
251
|
+
loaded_skill = self.registry.get(skill_name)
|
|
252
|
+
|
|
253
|
+
# If not found by name, try by type (for built-in skills)
|
|
254
|
+
if not loaded_skill:
|
|
255
|
+
loaded_skill = self.registry.get_by_type(skill_type)
|
|
256
|
+
|
|
257
|
+
if not loaded_skill:
|
|
258
|
+
logger.warning(
|
|
259
|
+
"skill_not_found_in_registry",
|
|
260
|
+
name=skill_name,
|
|
261
|
+
type=skill_type,
|
|
262
|
+
available_skills=[s.name for s in self.registry.list_skills()],
|
|
263
|
+
)
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
# Get runtime-appropriate implementation
|
|
267
|
+
impl = self.registry.get_implementation_for_runtime(
|
|
268
|
+
loaded_skill, self.runtime_type
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if not impl:
|
|
272
|
+
logger.error(
|
|
273
|
+
"no_implementation_for_runtime",
|
|
274
|
+
skill=loaded_skill.name,
|
|
275
|
+
runtime=self.runtime_type,
|
|
276
|
+
available_runtimes=list(loaded_skill.implementations.keys()),
|
|
277
|
+
)
|
|
278
|
+
return None
|
|
279
|
+
|
|
280
|
+
# Check if this is a builtin implementation (like Claude Code SDK tools)
|
|
281
|
+
if isinstance(impl, dict) and impl.get("builtin"):
|
|
282
|
+
builtin_tools = impl.get("tools", [])
|
|
283
|
+
|
|
284
|
+
logger.info(
|
|
285
|
+
"skill_builtin",
|
|
286
|
+
skill=loaded_skill.name,
|
|
287
|
+
runtime=self.runtime_type,
|
|
288
|
+
tools=builtin_tools,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# For builtin skills, return metadata - runtime handles tool mapping
|
|
292
|
+
builtin_skill_dict = {
|
|
293
|
+
"skill_name": loaded_skill.name,
|
|
294
|
+
"skill_type": loaded_skill.skill_type,
|
|
295
|
+
"builtin": True,
|
|
296
|
+
"tools": builtin_tools,
|
|
297
|
+
"config": config,
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
# UNIVERSAL VALIDATION: Validate builtin tool names
|
|
301
|
+
validated_builtin = self._validate_skill_tools(builtin_skill_dict, loaded_skill.name)
|
|
302
|
+
return validated_builtin
|
|
303
|
+
|
|
304
|
+
# Prepare configuration for Python class instantiation
|
|
305
|
+
instantiation_config = config.copy()
|
|
306
|
+
|
|
307
|
+
# Inject workspace directory for file/shell skills if not explicitly set
|
|
308
|
+
if loaded_skill.skill_type in ["file_system", "shell", "bash", "file", "file_generation"]:
|
|
309
|
+
from control_plane_api.worker.utils.workspace_manager import (
|
|
310
|
+
ensure_workspace,
|
|
311
|
+
should_use_custom_base_directory,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# Only inject workspace if user hasn't explicitly set base_directory
|
|
315
|
+
if execution_id and not should_use_custom_base_directory(skill_data):
|
|
316
|
+
try:
|
|
317
|
+
workspace_path = ensure_workspace(execution_id)
|
|
318
|
+
if workspace_path:
|
|
319
|
+
instantiation_config["base_directory"] = str(workspace_path)
|
|
320
|
+
|
|
321
|
+
logger.info(
|
|
322
|
+
"skill_using_execution_workspace",
|
|
323
|
+
skill=loaded_skill.name,
|
|
324
|
+
execution_id=execution_id[:8] if len(execution_id) >= 8 else execution_id,
|
|
325
|
+
workspace=str(workspace_path),
|
|
326
|
+
)
|
|
327
|
+
except Exception as e:
|
|
328
|
+
logger.warning(
|
|
329
|
+
"workspace_creation_failed_for_skill",
|
|
330
|
+
skill=loaded_skill.name,
|
|
331
|
+
execution_id=execution_id[:8] if len(execution_id) >= 8 else execution_id,
|
|
332
|
+
error=str(e),
|
|
333
|
+
error_type=type(e).__name__,
|
|
334
|
+
fallback="using_default_or_current_directory",
|
|
335
|
+
)
|
|
336
|
+
# Continue without workspace injection - skill will use its default
|
|
337
|
+
|
|
338
|
+
# Inject execution_id if provided
|
|
339
|
+
if execution_id:
|
|
340
|
+
instantiation_config['execution_id'] = execution_id
|
|
341
|
+
|
|
342
|
+
# Inject other runtime-specific config
|
|
343
|
+
# (e.g., API keys from environment variables)
|
|
344
|
+
self._inject_env_vars(instantiation_config, loaded_skill)
|
|
345
|
+
|
|
346
|
+
# Instantiate with configuration
|
|
347
|
+
try:
|
|
348
|
+
instance = impl(**instantiation_config)
|
|
349
|
+
|
|
350
|
+
logger.info(
|
|
351
|
+
"skill_instantiated",
|
|
352
|
+
skill=loaded_skill.name,
|
|
353
|
+
runtime=self.runtime_type,
|
|
354
|
+
implementation=impl.__name__,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
# UNIVERSAL VALIDATION: Validate all tool names before returning
|
|
358
|
+
validated_instance = self._validate_skill_tools(instance, loaded_skill.name)
|
|
359
|
+
|
|
360
|
+
return validated_instance
|
|
361
|
+
|
|
362
|
+
except Exception as e:
|
|
363
|
+
logger.error(
|
|
364
|
+
"skill_instantiation_failed",
|
|
365
|
+
skill=loaded_skill.name,
|
|
366
|
+
error=str(e),
|
|
367
|
+
exc_info=True,
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
# Note: Error event publishing removed to avoid asyncio event loop issues
|
|
371
|
+
# The error is already logged above and the skill will be skipped
|
|
372
|
+
# This prevents "bound to a different event loop" errors in synchronous contexts
|
|
373
|
+
|
|
374
|
+
return None
|
|
375
|
+
|
|
376
|
+
def create_skills_from_list(
|
|
377
|
+
self, skill_configs: List[dict], execution_id: Optional[str] = None
|
|
378
|
+
) -> List[Any]:
|
|
379
|
+
"""
|
|
380
|
+
Create multiple skills from configurations.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
skill_configs: List of skill config dicts
|
|
384
|
+
execution_id: Optional execution ID to inject into all skills
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
List of instantiated skills (non-None)
|
|
388
|
+
"""
|
|
389
|
+
skills = []
|
|
390
|
+
|
|
391
|
+
for config in skill_configs:
|
|
392
|
+
# Inject execution_id if provided
|
|
393
|
+
if execution_id:
|
|
394
|
+
config = config.copy()
|
|
395
|
+
config['execution_id'] = execution_id
|
|
396
|
+
|
|
397
|
+
skill = self.create_skill(config)
|
|
398
|
+
if skill:
|
|
399
|
+
skills.append(skill)
|
|
400
|
+
|
|
401
|
+
logger.info(
|
|
402
|
+
"skills_batch_created",
|
|
403
|
+
requested=len(skill_configs),
|
|
404
|
+
created=len(skills),
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
return skills
|
|
408
|
+
|
|
409
|
+
def _inject_env_vars(self, config: dict, skill: LoadedSkill):
|
|
410
|
+
"""
|
|
411
|
+
Inject environment variables into skill configuration.
|
|
412
|
+
|
|
413
|
+
Looks for environment variables defined in skill manifest.
|
|
414
|
+
"""
|
|
415
|
+
env_vars = skill.manifest.get("spec", {}).get("environmentVariables", [])
|
|
416
|
+
|
|
417
|
+
for env_var_def in env_vars:
|
|
418
|
+
var_name = env_var_def.get("name")
|
|
419
|
+
required = env_var_def.get("required", False)
|
|
420
|
+
|
|
421
|
+
# Check if already in config
|
|
422
|
+
if var_name.lower() in config or var_name in config:
|
|
423
|
+
continue
|
|
424
|
+
|
|
425
|
+
# Try to get from environment
|
|
426
|
+
env_value = os.environ.get(var_name)
|
|
427
|
+
|
|
428
|
+
if env_value:
|
|
429
|
+
# Convert env var name to config key (lowercase)
|
|
430
|
+
config_key = var_name.lower()
|
|
431
|
+
config[config_key] = env_value
|
|
432
|
+
logger.debug(
|
|
433
|
+
"injected_env_var",
|
|
434
|
+
skill=skill.name,
|
|
435
|
+
var_name=var_name,
|
|
436
|
+
)
|
|
437
|
+
elif required:
|
|
438
|
+
logger.warning(
|
|
439
|
+
"required_env_var_missing",
|
|
440
|
+
skill=skill.name,
|
|
441
|
+
var_name=var_name,
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
def get_available_skills(self) -> List[str]:
|
|
445
|
+
"""Get list of all available skill names."""
|
|
446
|
+
if not self._initialized:
|
|
447
|
+
self.initialize()
|
|
448
|
+
|
|
449
|
+
return [skill.name for skill in self.registry.list_skills()]
|
|
450
|
+
|
|
451
|
+
def get_skill_info(self, skill_name: str) -> Optional[dict]:
|
|
452
|
+
"""Get information about a specific skill."""
|
|
453
|
+
if not self._initialized:
|
|
454
|
+
self.initialize()
|
|
455
|
+
|
|
456
|
+
skill = self.registry.get(skill_name)
|
|
457
|
+
if not skill:
|
|
458
|
+
return None
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
"name": skill.name,
|
|
462
|
+
"version": skill.version,
|
|
463
|
+
"type": skill.skill_type,
|
|
464
|
+
"source": skill.source.value,
|
|
465
|
+
"runtimes": list(skill.implementations.keys()),
|
|
466
|
+
"metadata": skill.manifest.get("metadata", {}),
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
# Backward compatibility alias
|
|
470
|
+
# Old code using SkillFactoryV2 will still work
|
|
471
|
+
SkillFactoryV2 = SkillFactory
|