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,245 @@
|
|
|
1
|
+
"""Integration tests for builtin skills fixes (import errors, data_visualization, MCP)."""
|
|
2
|
+
import pytest
|
|
3
|
+
import asyncio
|
|
4
|
+
from control_plane_api.worker.services.skill_factory import SkillFactory
|
|
5
|
+
from control_plane_api.worker.runtimes.claude_code.mcp_discovery import discover_mcp_resources
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestImportFixes:
|
|
9
|
+
"""Test that import errors are fixed."""
|
|
10
|
+
|
|
11
|
+
def test_agent_executor_v2_imports(self):
|
|
12
|
+
"""Test that agent_executor_v2 imports correctly."""
|
|
13
|
+
from control_plane_api.worker.services.agent_executor_v2 import AgentExecutorServiceV2
|
|
14
|
+
assert AgentExecutorServiceV2 is not None
|
|
15
|
+
|
|
16
|
+
def test_team_executor_v2_imports(self):
|
|
17
|
+
"""Test that team_executor_v2 imports correctly."""
|
|
18
|
+
from control_plane_api.worker.services.team_executor_v2 import TeamExecutorServiceV2
|
|
19
|
+
assert TeamExecutorServiceV2 is not None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestDataVisualizationSkillRestoration:
|
|
23
|
+
"""Test that data_visualization skill is properly restored."""
|
|
24
|
+
|
|
25
|
+
def test_data_visualization_skill_yaml_exists(self):
|
|
26
|
+
"""Test that skill.yaml exists."""
|
|
27
|
+
import os
|
|
28
|
+
skill_yaml_path = "control_plane_api/worker/skills/builtin/data_visualization/skill.yaml"
|
|
29
|
+
assert os.path.exists(skill_yaml_path), "skill.yaml should exist"
|
|
30
|
+
|
|
31
|
+
def test_data_visualization_agno_impl_exists(self):
|
|
32
|
+
"""Test that agno_impl.py exists."""
|
|
33
|
+
import os
|
|
34
|
+
agno_impl_path = "control_plane_api/worker/skills/builtin/data_visualization/agno_impl.py"
|
|
35
|
+
assert os.path.exists(agno_impl_path), "agno_impl.py should exist"
|
|
36
|
+
|
|
37
|
+
def test_data_visualization_imports(self):
|
|
38
|
+
"""Test that data_visualization skill imports correctly."""
|
|
39
|
+
from control_plane_api.worker.skills.builtin.data_visualization.agno_impl import DataVisualizationTools
|
|
40
|
+
assert DataVisualizationTools is not None
|
|
41
|
+
|
|
42
|
+
def test_data_visualization_toolkit_instantiation(self):
|
|
43
|
+
"""Test that data_visualization toolkit can be instantiated."""
|
|
44
|
+
from control_plane_api.worker.skills.builtin.data_visualization.agno_impl import DataVisualizationTools
|
|
45
|
+
|
|
46
|
+
toolkit = DataVisualizationTools(
|
|
47
|
+
enable_flowchart=True,
|
|
48
|
+
enable_sequence=True,
|
|
49
|
+
max_diagram_size=50000
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
assert toolkit is not None
|
|
53
|
+
assert hasattr(toolkit, 'functions'), "Toolkit should have functions attribute"
|
|
54
|
+
|
|
55
|
+
# Should have 11 diagram tools
|
|
56
|
+
tool_count = len(toolkit.functions)
|
|
57
|
+
assert tool_count == 11, f"Expected 11 tools, got {tool_count}"
|
|
58
|
+
|
|
59
|
+
def test_data_visualization_skill_loading_agno(self):
|
|
60
|
+
"""Test that data_visualization skill loads correctly in agno runtime."""
|
|
61
|
+
factory = SkillFactory(runtime_type="agno")
|
|
62
|
+
factory.initialize()
|
|
63
|
+
|
|
64
|
+
skill_config = {
|
|
65
|
+
"name": "data-visualization",
|
|
66
|
+
"type": "data_visualization",
|
|
67
|
+
"enabled": True,
|
|
68
|
+
"configuration": {
|
|
69
|
+
"enable_flowchart": True,
|
|
70
|
+
"max_diagram_size": 50000
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
skill = factory.create_skill(skill_config)
|
|
75
|
+
assert skill is not None, "Skill should be created"
|
|
76
|
+
assert hasattr(skill, 'functions'), "Skill should have functions"
|
|
77
|
+
assert len(skill.functions) == 11, f"Should have 11 tools, got {len(skill.functions)}"
|
|
78
|
+
|
|
79
|
+
def test_data_visualization_skill_loading_claude_code(self):
|
|
80
|
+
"""Test that data_visualization skill loads correctly in claude_code runtime."""
|
|
81
|
+
factory = SkillFactory(runtime_type="claude_code")
|
|
82
|
+
factory.initialize()
|
|
83
|
+
|
|
84
|
+
skill_config = {
|
|
85
|
+
"name": "data-visualization",
|
|
86
|
+
"type": "data_visualization",
|
|
87
|
+
"enabled": True,
|
|
88
|
+
"configuration": {
|
|
89
|
+
"enable_flowchart": True,
|
|
90
|
+
"max_diagram_size": 50000
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
skill = factory.create_skill(skill_config)
|
|
95
|
+
assert skill is not None, "Skill should be created"
|
|
96
|
+
# For claude_code, it should be a toolkit instance that will be converted to MCP
|
|
97
|
+
assert hasattr(skill, 'functions'), "Skill should have functions for MCP conversion"
|
|
98
|
+
|
|
99
|
+
def test_data_visualization_with_execution_id(self):
|
|
100
|
+
"""Test that data_visualization skill accepts execution_id parameter."""
|
|
101
|
+
factory = SkillFactory(runtime_type="claude_code")
|
|
102
|
+
factory.initialize()
|
|
103
|
+
|
|
104
|
+
skill_config = {
|
|
105
|
+
"name": "data-visualization",
|
|
106
|
+
"type": "data_visualization",
|
|
107
|
+
"enabled": True,
|
|
108
|
+
"configuration": {
|
|
109
|
+
"enable_flowchart": True,
|
|
110
|
+
"max_diagram_size": 50000
|
|
111
|
+
},
|
|
112
|
+
"execution_id": "test-exec-123" # This was causing the failure
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
skill = factory.create_skill(skill_config)
|
|
116
|
+
assert skill is not None, "Skill should be created even with execution_id"
|
|
117
|
+
assert hasattr(skill, 'functions'), "Skill should have functions"
|
|
118
|
+
assert len(skill.functions) == 11, "Should have all 11 diagram tools"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class TestContextGraphSearchMCPFix:
|
|
122
|
+
"""Test that context_graph_search MCP verification is fixed."""
|
|
123
|
+
|
|
124
|
+
@pytest.mark.asyncio
|
|
125
|
+
async def test_sdk_mcp_server_object_handling(self):
|
|
126
|
+
"""Test that SDK MCP server objects are handled correctly (not treated as config dicts)."""
|
|
127
|
+
from claude_agent_sdk import create_sdk_mcp_server, tool as mcp_tool
|
|
128
|
+
|
|
129
|
+
# Create a simple SDK MCP server
|
|
130
|
+
@mcp_tool("test_tool", "A test tool", {"arg": str})
|
|
131
|
+
async def test_tool(args: dict) -> dict:
|
|
132
|
+
return {"result": "test"}
|
|
133
|
+
|
|
134
|
+
sdk_server = create_sdk_mcp_server(
|
|
135
|
+
name="test-server",
|
|
136
|
+
version="1.0.0",
|
|
137
|
+
tools=[test_tool]
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# This should NOT raise an error - it should skip pre-discovery
|
|
141
|
+
result = await discover_mcp_resources("test-server", sdk_server)
|
|
142
|
+
|
|
143
|
+
assert result["server_name"] == "test-server"
|
|
144
|
+
# SDK servers are skipped, which means connected=True and skipped=True
|
|
145
|
+
assert result.get("skipped") == True, "SDK MCP server should be skipped"
|
|
146
|
+
# If skipped, connected should be True (means "will work")
|
|
147
|
+
if result.get("skipped"):
|
|
148
|
+
assert result["connected"] == True, "Skipped SDK servers should report as connected"
|
|
149
|
+
assert "error" not in result or result["error"] is None
|
|
150
|
+
|
|
151
|
+
@pytest.mark.asyncio
|
|
152
|
+
async def test_context_graph_search_mcp_creation(self):
|
|
153
|
+
"""Test that context_graph_search skill creates MCP server successfully."""
|
|
154
|
+
from control_plane_api.worker.runtimes.claude_code.mcp_builder import build_mcp_servers
|
|
155
|
+
from control_plane_api.worker.services.skill_factory import SkillFactory
|
|
156
|
+
|
|
157
|
+
# Create skill instance
|
|
158
|
+
factory = SkillFactory(runtime_type="claude_code")
|
|
159
|
+
factory.initialize()
|
|
160
|
+
|
|
161
|
+
skill_config = {
|
|
162
|
+
"name": "context-graph-search",
|
|
163
|
+
"type": "context_graph_search",
|
|
164
|
+
"enabled": True,
|
|
165
|
+
"configuration": {}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
skill = factory.create_skill(skill_config)
|
|
169
|
+
assert skill is not None
|
|
170
|
+
|
|
171
|
+
# Build MCP servers
|
|
172
|
+
mcp_servers, _ = build_mcp_servers([skill], {})
|
|
173
|
+
|
|
174
|
+
assert "context-graph-search" in mcp_servers, "Should create MCP server for context-graph-search"
|
|
175
|
+
|
|
176
|
+
# Verify the server can be discovered without errors
|
|
177
|
+
server = mcp_servers["context-graph-search"]
|
|
178
|
+
result = await discover_mcp_resources("context-graph-search", server)
|
|
179
|
+
|
|
180
|
+
# SDK servers should be skipped
|
|
181
|
+
assert result.get("skipped") == True, "SDK MCP servers should be skipped"
|
|
182
|
+
# If skipped, connected should be True
|
|
183
|
+
if result.get("skipped"):
|
|
184
|
+
assert result["connected"] == True, "Skipped SDK servers should report as connected"
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class TestSkillFactoryAutoInclude:
|
|
188
|
+
"""Test that context_graph_search is auto-included correctly."""
|
|
189
|
+
|
|
190
|
+
def test_context_graph_search_auto_include(self):
|
|
191
|
+
"""Test that context_graph_search is properly auto-included."""
|
|
192
|
+
skill_configs = []
|
|
193
|
+
|
|
194
|
+
# Auto-include logic from executor
|
|
195
|
+
builtin_skill_types = {'context_graph_search'}
|
|
196
|
+
existing_skill_types = {cfg.get('type') for cfg in skill_configs}
|
|
197
|
+
|
|
198
|
+
for builtin_type in builtin_skill_types:
|
|
199
|
+
if builtin_type not in existing_skill_types:
|
|
200
|
+
builtin_config = {
|
|
201
|
+
'name': builtin_type,
|
|
202
|
+
'type': builtin_type,
|
|
203
|
+
'enabled': True,
|
|
204
|
+
'configuration': {}
|
|
205
|
+
}
|
|
206
|
+
skill_configs.append(builtin_config)
|
|
207
|
+
|
|
208
|
+
assert len(skill_configs) == 1
|
|
209
|
+
assert skill_configs[0]['type'] == 'context_graph_search'
|
|
210
|
+
|
|
211
|
+
# Now try to load it
|
|
212
|
+
factory = SkillFactory(runtime_type="claude_code")
|
|
213
|
+
factory.initialize()
|
|
214
|
+
|
|
215
|
+
skill = factory.create_skill(skill_configs[0])
|
|
216
|
+
assert skill is not None
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class TestSkillRegistryStats:
|
|
220
|
+
"""Test that skill registry has expected skills."""
|
|
221
|
+
|
|
222
|
+
def test_builtin_skills_registered(self):
|
|
223
|
+
"""Test that all expected builtin skills are registered."""
|
|
224
|
+
factory = SkillFactory(runtime_type="agno")
|
|
225
|
+
factory.initialize()
|
|
226
|
+
|
|
227
|
+
stats = factory.registry.get_stats()
|
|
228
|
+
|
|
229
|
+
# Should have these builtin skills (using underscores - that's how they're registered)
|
|
230
|
+
expected_skills = {
|
|
231
|
+
'shell', 'file_system', 'python', 'docker',
|
|
232
|
+
'data_visualization', # Restored!
|
|
233
|
+
'context_graph_search', # Note: underscore, not hyphen
|
|
234
|
+
'workflow_executor', 'file_generation'
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
registered_skills = set(stats['skills_by_type'].keys())
|
|
238
|
+
|
|
239
|
+
for skill in expected_skills:
|
|
240
|
+
assert skill in registered_skills, f"Expected skill '{skill}' not registered. Registered: {registered_skills}"
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
if __name__ == "__main__":
|
|
244
|
+
# Run tests
|
|
245
|
+
pytest.main([__file__, "-v", "-s"])
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"""Integration tests for ContextGraphSearchTools with both runtimes."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import json
|
|
5
|
+
from unittest.mock import Mock, patch, MagicMock
|
|
6
|
+
import asyncio
|
|
7
|
+
|
|
8
|
+
# Add worker to sys.path
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
12
|
+
|
|
13
|
+
from skills.builtin.context_graph_search.agno_impl import ContextGraphSearchTools
|
|
14
|
+
from services.skill_factory import SkillFactory
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestContextGraphSearchAgnoIntegration:
|
|
18
|
+
"""Integration tests for ContextGraphSearchTools with Agno runtime"""
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def mock_env_vars(self, monkeypatch):
|
|
22
|
+
"""Set up environment variables for testing"""
|
|
23
|
+
monkeypatch.setenv("KUBIYA_API_KEY", "test_api_key_123")
|
|
24
|
+
monkeypatch.setenv("CONTEXT_GRAPH_API_BASE", "https://test-graph.kubiya.ai")
|
|
25
|
+
monkeypatch.setenv("KUBIYA_ORG_ID", "test_org_123")
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def skill_factory(self):
|
|
29
|
+
"""Create SkillFactory instance"""
|
|
30
|
+
factory = SkillFactory(runtime_type="agno")
|
|
31
|
+
factory.initialize()
|
|
32
|
+
return factory
|
|
33
|
+
|
|
34
|
+
def test_skill_factory_creates_context_graph_tools(self, skill_factory, mock_env_vars):
|
|
35
|
+
"""Test that SkillFactory can create ContextGraphSearchTools"""
|
|
36
|
+
skill_configs = [
|
|
37
|
+
{
|
|
38
|
+
"name": "context_graph_search",
|
|
39
|
+
"type": "context_graph_search",
|
|
40
|
+
"enabled": True,
|
|
41
|
+
"configuration": {}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
skills = skill_factory.create_skills_from_list(skill_configs)
|
|
46
|
+
|
|
47
|
+
assert len(skills) == 1
|
|
48
|
+
assert type(skills[0]).__name__ == 'ContextGraphSearchTools'
|
|
49
|
+
|
|
50
|
+
def test_skill_factory_with_custom_config(self, skill_factory, mock_env_vars):
|
|
51
|
+
"""Test SkillFactory creates tools with custom configuration"""
|
|
52
|
+
skill_configs = [
|
|
53
|
+
{
|
|
54
|
+
"name": "context_graph_search",
|
|
55
|
+
"type": "context_graph_search",
|
|
56
|
+
"enabled": True,
|
|
57
|
+
"configuration": {
|
|
58
|
+
"timeout": 60,
|
|
59
|
+
"default_limit": 50
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
skills = skill_factory.create_skills_from_list(skill_configs)
|
|
65
|
+
|
|
66
|
+
assert len(skills) == 1
|
|
67
|
+
tool = skills[0]
|
|
68
|
+
assert tool.timeout == 60
|
|
69
|
+
assert tool.default_limit == 50
|
|
70
|
+
|
|
71
|
+
@patch('skills.builtin.context_graph_search.agno_impl.httpx.Client')
|
|
72
|
+
def test_agno_runtime_tool_execution(self, mock_client_class, mock_env_vars):
|
|
73
|
+
"""Test executing a tool in Agno runtime context"""
|
|
74
|
+
mock_response = Mock()
|
|
75
|
+
mock_response.status_code = 200
|
|
76
|
+
mock_response.json.return_value = {
|
|
77
|
+
"labels": ["User", "Repository", "Service"]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
mock_client = MagicMock()
|
|
81
|
+
mock_client.__enter__.return_value.get.return_value = mock_response
|
|
82
|
+
mock_client_class.return_value = mock_client
|
|
83
|
+
|
|
84
|
+
# Create tool instance
|
|
85
|
+
tools = ContextGraphSearchTools()
|
|
86
|
+
|
|
87
|
+
# Execute tool method
|
|
88
|
+
result = tools.get_labels()
|
|
89
|
+
|
|
90
|
+
# Verify result
|
|
91
|
+
assert isinstance(result, str)
|
|
92
|
+
parsed = json.loads(result)
|
|
93
|
+
assert "labels" in parsed
|
|
94
|
+
assert len(parsed["labels"]) == 3
|
|
95
|
+
|
|
96
|
+
# Verify HTTP call was made correctly
|
|
97
|
+
mock_client.__enter__.return_value.get.assert_called_once()
|
|
98
|
+
call_args = mock_client.__enter__.return_value.get.call_args
|
|
99
|
+
assert "https://test-graph.kubiya.ai/api/v1/graph/labels" in call_args[0][0]
|
|
100
|
+
|
|
101
|
+
def test_toolkit_integration_with_agno_functions(self, mock_env_vars):
|
|
102
|
+
"""Test that toolkit properly registers functions for Agno"""
|
|
103
|
+
tools = ContextGraphSearchTools()
|
|
104
|
+
|
|
105
|
+
# Verify toolkit has functions attribute (required by Agno)
|
|
106
|
+
assert hasattr(tools, "functions")
|
|
107
|
+
assert isinstance(tools.functions, dict)
|
|
108
|
+
assert len(tools.functions) >= 9
|
|
109
|
+
|
|
110
|
+
# Verify each function has proper structure
|
|
111
|
+
for func_name, func_obj in tools.functions.items():
|
|
112
|
+
# Verify function object has required attributes
|
|
113
|
+
assert hasattr(func_obj, "entrypoint"), f"{func_name} missing entrypoint"
|
|
114
|
+
assert callable(func_obj.entrypoint), f"{func_name} entrypoint not callable"
|
|
115
|
+
|
|
116
|
+
# Verify function has description
|
|
117
|
+
description = getattr(func_obj, "description", None) or func_obj.entrypoint.__doc__
|
|
118
|
+
assert description, f"{func_name} missing description"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class TestContextGraphSearchClaudeCodeIntegration:
|
|
122
|
+
"""Integration tests for ContextGraphSearchTools with Claude Code runtime"""
|
|
123
|
+
|
|
124
|
+
@pytest.fixture
|
|
125
|
+
def mock_env_vars(self, monkeypatch):
|
|
126
|
+
"""Set up environment variables for testing"""
|
|
127
|
+
monkeypatch.setenv("KUBIYA_API_KEY", "test_api_key_123")
|
|
128
|
+
monkeypatch.setenv("CONTEXT_GRAPH_API_BASE", "https://test-graph.kubiya.ai")
|
|
129
|
+
|
|
130
|
+
@pytest.fixture
|
|
131
|
+
def skill_factory(self):
|
|
132
|
+
"""Create SkillFactory instance for Claude Code"""
|
|
133
|
+
factory = SkillFactory(runtime_type="claude_code")
|
|
134
|
+
factory.initialize()
|
|
135
|
+
return factory
|
|
136
|
+
|
|
137
|
+
def test_skill_factory_creates_tools_for_claude_code(self, skill_factory, mock_env_vars):
|
|
138
|
+
"""Test that SkillFactory can create tools for Claude Code runtime"""
|
|
139
|
+
skill_configs = [
|
|
140
|
+
{
|
|
141
|
+
"name": "context_graph_search",
|
|
142
|
+
"type": "context_graph_search",
|
|
143
|
+
"enabled": True,
|
|
144
|
+
"configuration": {}
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
skills = skill_factory.create_skills_from_list(skill_configs)
|
|
149
|
+
|
|
150
|
+
assert len(skills) == 1
|
|
151
|
+
assert type(skills[0]).__name__ == 'ContextGraphSearchTools'
|
|
152
|
+
|
|
153
|
+
@pytest.mark.asyncio
|
|
154
|
+
async def test_mcp_conversion(self, mock_env_vars):
|
|
155
|
+
"""Test that tools can be converted to MCP server format"""
|
|
156
|
+
from runtimes.claude_code.mcp_builder import build_mcp_servers
|
|
157
|
+
|
|
158
|
+
# Create skill instance
|
|
159
|
+
tools = ContextGraphSearchTools()
|
|
160
|
+
|
|
161
|
+
# Convert to MCP servers
|
|
162
|
+
mcp_servers, _ = build_mcp_servers(skills=[tools])
|
|
163
|
+
|
|
164
|
+
# Verify MCP server was created
|
|
165
|
+
assert "context-graph-search" in mcp_servers
|
|
166
|
+
mcp_server = mcp_servers["context-graph-search"]
|
|
167
|
+
|
|
168
|
+
# Verify it's a valid MCP server object
|
|
169
|
+
assert mcp_server is not None
|
|
170
|
+
|
|
171
|
+
def test_toolkit_functions_for_mcp_conversion(self, mock_env_vars):
|
|
172
|
+
"""Test that toolkit functions can be converted to MCP tools"""
|
|
173
|
+
tools = ContextGraphSearchTools()
|
|
174
|
+
|
|
175
|
+
# Verify functions registry exists (required for MCP conversion)
|
|
176
|
+
assert hasattr(tools, "functions")
|
|
177
|
+
assert len(tools.functions) >= 9
|
|
178
|
+
|
|
179
|
+
# Each function should have the structure needed for MCP conversion
|
|
180
|
+
expected_tools = [
|
|
181
|
+
"search_nodes",
|
|
182
|
+
"get_node",
|
|
183
|
+
"get_relationships",
|
|
184
|
+
"get_subgraph",
|
|
185
|
+
"search_by_text",
|
|
186
|
+
"execute_query",
|
|
187
|
+
"get_labels",
|
|
188
|
+
"get_relationship_types",
|
|
189
|
+
"get_stats"
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
for tool_name in expected_tools:
|
|
193
|
+
assert tool_name in tools.functions
|
|
194
|
+
func_obj = tools.functions[tool_name]
|
|
195
|
+
|
|
196
|
+
# Verify function has entrypoint (required for MCP wrapping)
|
|
197
|
+
assert hasattr(func_obj, "entrypoint")
|
|
198
|
+
assert callable(func_obj.entrypoint)
|
|
199
|
+
|
|
200
|
+
# Verify function has metadata (description, parameters)
|
|
201
|
+
assert hasattr(func_obj, "description") or func_obj.entrypoint.__doc__
|
|
202
|
+
|
|
203
|
+
@pytest.mark.asyncio
|
|
204
|
+
@patch('skills.builtin.context_graph_search.agno_impl.httpx.Client')
|
|
205
|
+
async def test_mcp_tool_execution(self, mock_client_class, mock_env_vars):
|
|
206
|
+
"""Test executing a tool through MCP wrapper"""
|
|
207
|
+
mock_response = Mock()
|
|
208
|
+
mock_response.status_code = 200
|
|
209
|
+
mock_response.json.return_value = {
|
|
210
|
+
"nodes": [{"id": "node1", "label": "User"}]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
mock_client = MagicMock()
|
|
214
|
+
mock_client.__enter__.return_value.post.return_value = mock_response
|
|
215
|
+
mock_client_class.return_value = mock_client
|
|
216
|
+
|
|
217
|
+
# Create tool instance
|
|
218
|
+
tools = ContextGraphSearchTools()
|
|
219
|
+
|
|
220
|
+
# Get the function from registry
|
|
221
|
+
search_func = tools.functions["search_nodes"]
|
|
222
|
+
entrypoint = search_func.entrypoint
|
|
223
|
+
|
|
224
|
+
# Execute through entrypoint (simulating MCP call)
|
|
225
|
+
result = entrypoint(label="User")
|
|
226
|
+
|
|
227
|
+
# Verify result is JSON string
|
|
228
|
+
assert isinstance(result, str)
|
|
229
|
+
parsed = json.loads(result)
|
|
230
|
+
assert "nodes" in parsed
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class TestContextGraphSearchSkillDiscovery:
|
|
234
|
+
"""Test skill discovery and loading mechanisms"""
|
|
235
|
+
|
|
236
|
+
@pytest.fixture
|
|
237
|
+
def mock_env_vars(self, monkeypatch):
|
|
238
|
+
"""Set up environment variables"""
|
|
239
|
+
monkeypatch.setenv("KUBIYA_API_KEY", "test_key")
|
|
240
|
+
|
|
241
|
+
def test_skill_yaml_exists(self):
|
|
242
|
+
"""Test that skill.yaml file exists and is valid"""
|
|
243
|
+
from pathlib import Path
|
|
244
|
+
skill_dir = Path(__file__).parent.parent.parent / "skills" / "builtin" / "context_graph_search"
|
|
245
|
+
skill_yaml = skill_dir / "skill.yaml"
|
|
246
|
+
|
|
247
|
+
assert skill_yaml.exists(), "skill.yaml not found"
|
|
248
|
+
|
|
249
|
+
# Try to parse it
|
|
250
|
+
import yaml
|
|
251
|
+
with open(skill_yaml) as f:
|
|
252
|
+
skill_def = yaml.safe_load(f)
|
|
253
|
+
|
|
254
|
+
# Verify required fields
|
|
255
|
+
assert skill_def["apiVersion"] == "kubiya.ai/v1"
|
|
256
|
+
assert skill_def["kind"] == "Skill"
|
|
257
|
+
assert skill_def["metadata"]["name"] == "context-graph-search"
|
|
258
|
+
assert skill_def["spec"]["type"] == "context_graph_search"
|
|
259
|
+
|
|
260
|
+
# Verify implementations
|
|
261
|
+
assert "agno" in skill_def["spec"]["implementations"]
|
|
262
|
+
assert "claude_code" in skill_def["spec"]["implementations"]
|
|
263
|
+
|
|
264
|
+
def test_agno_impl_exists(self):
|
|
265
|
+
"""Test that agno_impl.py exists and exports ContextGraphSearchTools"""
|
|
266
|
+
from pathlib import Path
|
|
267
|
+
skill_dir = Path(__file__).parent.parent.parent / "skills" / "builtin" / "context_graph_search"
|
|
268
|
+
agno_impl = skill_dir / "agno_impl.py"
|
|
269
|
+
|
|
270
|
+
assert agno_impl.exists(), "agno_impl.py not found"
|
|
271
|
+
|
|
272
|
+
# Verify it can be imported
|
|
273
|
+
from skills.builtin.context_graph_search.agno_impl import ContextGraphSearchTools
|
|
274
|
+
assert ContextGraphSearchTools is not None
|
|
275
|
+
|
|
276
|
+
def test_skill_factory_can_discover_skill(self, mock_env_vars):
|
|
277
|
+
"""Test that SkillFactory can discover the context_graph_search skill"""
|
|
278
|
+
factory = SkillFactory(runtime_type="agno")
|
|
279
|
+
factory.initialize()
|
|
280
|
+
|
|
281
|
+
# Try to create the skill
|
|
282
|
+
skill_configs = [
|
|
283
|
+
{
|
|
284
|
+
"name": "context_graph_search",
|
|
285
|
+
"type": "context_graph_search",
|
|
286
|
+
"enabled": True,
|
|
287
|
+
"configuration": {}
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
skills = factory.create_skills_from_list(skill_configs)
|
|
292
|
+
|
|
293
|
+
# Verify skill was created
|
|
294
|
+
assert len(skills) == 1
|
|
295
|
+
assert type(skills[0]).__name__ == 'ContextGraphSearchTools'
|
|
296
|
+
|
|
297
|
+
def test_skill_can_be_imported(self):
|
|
298
|
+
"""Test that skill can be imported from __init__.py"""
|
|
299
|
+
from skills.builtin.context_graph_search import ContextGraphSearchTools
|
|
300
|
+
assert ContextGraphSearchTools is not None
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class TestContextGraphSearchErrorHandling:
|
|
304
|
+
"""Test error handling and edge cases"""
|
|
305
|
+
|
|
306
|
+
@pytest.fixture
|
|
307
|
+
def mock_env_vars(self, monkeypatch):
|
|
308
|
+
"""Set up environment variables"""
|
|
309
|
+
monkeypatch.setenv("KUBIYA_API_KEY", "test_key")
|
|
310
|
+
monkeypatch.setenv("CONTEXT_GRAPH_API_BASE", "https://test-graph.api")
|
|
311
|
+
|
|
312
|
+
@patch('skills.builtin.context_graph_search.agno_impl.httpx.Client')
|
|
313
|
+
def test_network_error_handling(self, mock_client_class, mock_env_vars):
|
|
314
|
+
"""Test handling of network errors"""
|
|
315
|
+
mock_client = MagicMock()
|
|
316
|
+
mock_client.__enter__.return_value.get.side_effect = Exception("Network error")
|
|
317
|
+
mock_client_class.return_value = mock_client
|
|
318
|
+
|
|
319
|
+
tools = ContextGraphSearchTools()
|
|
320
|
+
|
|
321
|
+
with pytest.raises(Exception, match="Request failed"):
|
|
322
|
+
tools.get_labels()
|
|
323
|
+
|
|
324
|
+
@patch('skills.builtin.context_graph_search.agno_impl.httpx.Client')
|
|
325
|
+
def test_invalid_json_response(self, mock_client_class, mock_env_vars):
|
|
326
|
+
"""Test handling of invalid JSON responses"""
|
|
327
|
+
mock_response = Mock()
|
|
328
|
+
mock_response.status_code = 200
|
|
329
|
+
mock_response.json.side_effect = json.JSONDecodeError("Invalid JSON", "", 0)
|
|
330
|
+
|
|
331
|
+
mock_client = MagicMock()
|
|
332
|
+
mock_client.__enter__.return_value.get.return_value = mock_response
|
|
333
|
+
mock_client_class.return_value = mock_client
|
|
334
|
+
|
|
335
|
+
tools = ContextGraphSearchTools()
|
|
336
|
+
|
|
337
|
+
with pytest.raises(Exception):
|
|
338
|
+
tools.get_labels()
|
|
339
|
+
|
|
340
|
+
def test_missing_api_key(self, monkeypatch):
|
|
341
|
+
"""Test behavior when API key is missing"""
|
|
342
|
+
monkeypatch.delenv("KUBIYA_API_KEY", raising=False)
|
|
343
|
+
|
|
344
|
+
# Should still create tools but with warning
|
|
345
|
+
tools = ContextGraphSearchTools()
|
|
346
|
+
assert tools.api_key is None
|
|
347
|
+
|
|
348
|
+
@patch('skills.builtin.context_graph_search.agno_impl.httpx.Client')
|
|
349
|
+
def test_empty_response_handling(self, mock_client_class, mock_env_vars):
|
|
350
|
+
"""Test handling of empty responses"""
|
|
351
|
+
mock_response = Mock()
|
|
352
|
+
mock_response.status_code = 200
|
|
353
|
+
mock_response.json.return_value = {}
|
|
354
|
+
|
|
355
|
+
mock_client = MagicMock()
|
|
356
|
+
mock_client.__enter__.return_value.get.return_value = mock_response
|
|
357
|
+
mock_client_class.return_value = mock_client
|
|
358
|
+
|
|
359
|
+
tools = ContextGraphSearchTools()
|
|
360
|
+
result = tools.get_labels()
|
|
361
|
+
|
|
362
|
+
# Should still return valid JSON string
|
|
363
|
+
assert isinstance(result, str)
|
|
364
|
+
parsed = json.loads(result)
|
|
365
|
+
assert parsed == {}
|