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,59 @@
|
|
|
1
|
+
"""Authentication validation endpoints for delegated auth from other services."""
|
|
2
|
+
|
|
3
|
+
from fastapi import APIRouter, Depends
|
|
4
|
+
from typing import Dict
|
|
5
|
+
import structlog
|
|
6
|
+
|
|
7
|
+
from control_plane_api.app.middleware.auth import get_current_organization
|
|
8
|
+
|
|
9
|
+
logger = structlog.get_logger()
|
|
10
|
+
|
|
11
|
+
router = APIRouter(prefix="/api/v1/auth", tags=["authentication"])
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@router.get("/validate")
|
|
15
|
+
async def validate_token(
|
|
16
|
+
organization: dict = Depends(get_current_organization)
|
|
17
|
+
) -> Dict:
|
|
18
|
+
"""
|
|
19
|
+
Validate authentication token and return organization data.
|
|
20
|
+
|
|
21
|
+
This endpoint allows other services (like context-graph-api) to validate
|
|
22
|
+
tokens without duplicating auth logic. The control plane handles all
|
|
23
|
+
validation, caching, and Kubiya API integration.
|
|
24
|
+
|
|
25
|
+
The token should be passed in the Authorization header:
|
|
26
|
+
- Bearer <token> for user JWT tokens
|
|
27
|
+
- UserKey <token> for worker/API key tokens
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Organization dict with user and org information:
|
|
31
|
+
{
|
|
32
|
+
"id": "org-slug",
|
|
33
|
+
"name": "Organization Name",
|
|
34
|
+
"slug": "org-slug",
|
|
35
|
+
"user_id": "user-uuid",
|
|
36
|
+
"user_email": "user@example.com",
|
|
37
|
+
"user_name": "User Name",
|
|
38
|
+
"user_avatar": "...",
|
|
39
|
+
"user_status": "...",
|
|
40
|
+
"user_groups": [...]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
401: Invalid or expired token
|
|
45
|
+
500: Internal server error
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
```bash
|
|
49
|
+
curl -H "Authorization: Bearer <token>" \\
|
|
50
|
+
https://control-plane.kubiya.ai/api/v1/auth/validate
|
|
51
|
+
```
|
|
52
|
+
"""
|
|
53
|
+
logger.info(
|
|
54
|
+
"auth_validation_delegated",
|
|
55
|
+
org_slug=organization["slug"],
|
|
56
|
+
user_id=organization.get("user_id"),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return organization
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Client Configuration Router
|
|
3
|
+
|
|
4
|
+
Provides configuration endpoints for CLI and other clients to discover
|
|
5
|
+
backend service URLs and credentials.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from fastapi import APIRouter, Depends
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
from control_plane_api.app.middleware.auth import get_current_organization
|
|
13
|
+
from control_plane_api.app.config import get_api_config
|
|
14
|
+
|
|
15
|
+
settings = get_api_config()
|
|
16
|
+
|
|
17
|
+
router = APIRouter(prefix="/client", tags=["client-config"])
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ClientConfig(BaseModel):
|
|
21
|
+
"""Configuration for CLI clients."""
|
|
22
|
+
|
|
23
|
+
# Backend service URLs
|
|
24
|
+
context_graph_api_base: str
|
|
25
|
+
|
|
26
|
+
# Future: LLM credentials (for direct client-side agent execution)
|
|
27
|
+
# litellm_api_base: Optional[str] = None
|
|
28
|
+
# litellm_api_key: Optional[str] = None
|
|
29
|
+
|
|
30
|
+
# Future: Temporal configuration
|
|
31
|
+
# temporal_address: Optional[str] = None
|
|
32
|
+
# temporal_namespace: Optional[str] = None
|
|
33
|
+
|
|
34
|
+
# Organization context
|
|
35
|
+
organization_id: str
|
|
36
|
+
organization_name: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@router.get("/config", response_model=ClientConfig)
|
|
40
|
+
async def get_client_config(
|
|
41
|
+
organization: dict = Depends(get_current_organization),
|
|
42
|
+
):
|
|
43
|
+
"""
|
|
44
|
+
Get client configuration including backend service URLs.
|
|
45
|
+
|
|
46
|
+
This endpoint allows CLI clients to discover the context graph API URL
|
|
47
|
+
and other service endpoints, enabling direct connections without proxying
|
|
48
|
+
through the control plane.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
ClientConfig with service URLs and credentials
|
|
52
|
+
"""
|
|
53
|
+
return ClientConfig(
|
|
54
|
+
context_graph_api_base=settings.context_graph_api_base,
|
|
55
|
+
organization_id=organization["id"],
|
|
56
|
+
organization_name=organization.get("name", organization["id"]),
|
|
57
|
+
)
|
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Context Graph Router - Proxy to Context Graph API
|
|
3
|
+
|
|
4
|
+
This router provides access to the Context Graph API (Neo4j-based context graphs)
|
|
5
|
+
with org and integration namespaces. All endpoints are proxied with authentication.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
from fastapi import APIRouter, Depends, HTTPException, Request, Response
|
|
10
|
+
from typing import Optional, Dict, Any
|
|
11
|
+
import structlog
|
|
12
|
+
|
|
13
|
+
from control_plane_api.app.middleware.auth import get_current_organization
|
|
14
|
+
from control_plane_api.app.config import settings
|
|
15
|
+
|
|
16
|
+
logger = structlog.get_logger()
|
|
17
|
+
|
|
18
|
+
router = APIRouter(prefix="/context-graph", tags=["context-graph"])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def proxy_graph_request(
|
|
22
|
+
request: Request,
|
|
23
|
+
path: str,
|
|
24
|
+
method: str = "GET",
|
|
25
|
+
query_params: Optional[Dict[str, Any]] = None,
|
|
26
|
+
body: Optional[Dict[str, Any]] = None,
|
|
27
|
+
organization: dict = None,
|
|
28
|
+
) -> Response:
|
|
29
|
+
"""
|
|
30
|
+
Generic proxy function for Context Graph API requests.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
request: FastAPI request object
|
|
34
|
+
path: Path to proxy (e.g., "/api/v1/graph/nodes")
|
|
35
|
+
method: HTTP method
|
|
36
|
+
query_params: Query parameters
|
|
37
|
+
body: Request body (for POST requests)
|
|
38
|
+
organization: Organization context
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
FastAPI Response with proxied content
|
|
42
|
+
"""
|
|
43
|
+
try:
|
|
44
|
+
token = request.state.kubiya_token
|
|
45
|
+
auth_type = getattr(request.state, "kubiya_auth_type", "Bearer")
|
|
46
|
+
org_id = organization["id"] if organization else None
|
|
47
|
+
|
|
48
|
+
# Prepare headers for Context Graph API
|
|
49
|
+
headers = {
|
|
50
|
+
"Authorization": f"{auth_type} {token}",
|
|
51
|
+
"Accept": "application/json",
|
|
52
|
+
"Content-Type": "application/json",
|
|
53
|
+
"X-Kubiya-Client": "agent-control-plane",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if org_id:
|
|
57
|
+
headers["X-Organization-ID"] = org_id
|
|
58
|
+
|
|
59
|
+
# Forward Accept-Encoding header to disable gzip if requested by client
|
|
60
|
+
if "accept-encoding" in request.headers:
|
|
61
|
+
headers["Accept-Encoding"] = request.headers["accept-encoding"]
|
|
62
|
+
|
|
63
|
+
# Build full URL
|
|
64
|
+
base_url = settings.context_graph_api_base.rstrip("/")
|
|
65
|
+
full_url = f"{base_url}{path}"
|
|
66
|
+
|
|
67
|
+
# Make request to Context Graph API
|
|
68
|
+
async with httpx.AsyncClient(timeout=settings.context_graph_api_timeout) as client:
|
|
69
|
+
if method == "GET":
|
|
70
|
+
response = await client.get(full_url, headers=headers, params=query_params)
|
|
71
|
+
elif method == "POST":
|
|
72
|
+
response = await client.post(full_url, headers=headers, params=query_params, json=body)
|
|
73
|
+
elif method == "PUT":
|
|
74
|
+
response = await client.put(full_url, headers=headers, params=query_params, json=body)
|
|
75
|
+
elif method == "DELETE":
|
|
76
|
+
response = await client.delete(full_url, headers=headers, params=query_params)
|
|
77
|
+
else:
|
|
78
|
+
raise HTTPException(status_code=405, detail=f"Method {method} not allowed")
|
|
79
|
+
|
|
80
|
+
logger.info(
|
|
81
|
+
"context_graph_request",
|
|
82
|
+
org_id=org_id,
|
|
83
|
+
path=path,
|
|
84
|
+
method=method,
|
|
85
|
+
status=response.status_code,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Clean response headers - remove compression headers since we handle encoding
|
|
89
|
+
response_headers = dict(response.headers)
|
|
90
|
+
# Remove headers that might cause decompression issues
|
|
91
|
+
response_headers.pop("content-encoding", None)
|
|
92
|
+
response_headers.pop("content-length", None) # Will be recalculated
|
|
93
|
+
|
|
94
|
+
# Return response with original status code
|
|
95
|
+
return Response(
|
|
96
|
+
content=response.content,
|
|
97
|
+
status_code=response.status_code,
|
|
98
|
+
headers=response_headers,
|
|
99
|
+
media_type=response.headers.get("content-type", "application/json"),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
except httpx.TimeoutException:
|
|
103
|
+
logger.error("context_graph_timeout", path=path, method=method)
|
|
104
|
+
raise HTTPException(status_code=504, detail="Context Graph API request timed out")
|
|
105
|
+
except httpx.RequestError as e:
|
|
106
|
+
logger.error("context_graph_request_error", error=str(e), path=path)
|
|
107
|
+
raise HTTPException(status_code=502, detail=f"Failed to connect to Context Graph API: {str(e)}")
|
|
108
|
+
except HTTPException:
|
|
109
|
+
raise
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.error("context_graph_unexpected_error", error=str(e), error_type=type(e).__name__)
|
|
112
|
+
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@router.get("/health")
|
|
116
|
+
async def health_check(
|
|
117
|
+
request: Request,
|
|
118
|
+
organization: dict = Depends(get_current_organization),
|
|
119
|
+
):
|
|
120
|
+
"""Health check endpoint for Context Graph API."""
|
|
121
|
+
return await proxy_graph_request(
|
|
122
|
+
request=request,
|
|
123
|
+
path="/health",
|
|
124
|
+
method="GET",
|
|
125
|
+
organization=organization,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@router.post("/api/v1/graph/nodes/search")
|
|
130
|
+
async def search_nodes(
|
|
131
|
+
request: Request,
|
|
132
|
+
body: Dict[str, Any],
|
|
133
|
+
integration: Optional[str] = None,
|
|
134
|
+
skip: int = 0,
|
|
135
|
+
limit: int = 100,
|
|
136
|
+
organization: dict = Depends(get_current_organization),
|
|
137
|
+
):
|
|
138
|
+
"""
|
|
139
|
+
Search for nodes in the context graph.
|
|
140
|
+
|
|
141
|
+
Body should contain NodeSearchRequest:
|
|
142
|
+
- label: Optional node label to filter by
|
|
143
|
+
- property_name: Optional property name to filter by
|
|
144
|
+
- property_value: Optional property value to match
|
|
145
|
+
"""
|
|
146
|
+
query_params = {"skip": skip, "limit": limit}
|
|
147
|
+
if integration:
|
|
148
|
+
query_params["integration"] = integration
|
|
149
|
+
|
|
150
|
+
return await proxy_graph_request(
|
|
151
|
+
request=request,
|
|
152
|
+
path="/api/v1/graph/nodes/search",
|
|
153
|
+
method="POST",
|
|
154
|
+
query_params=query_params,
|
|
155
|
+
body=body,
|
|
156
|
+
organization=organization,
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@router.get("/api/v1/graph/nodes/{node_id}")
|
|
161
|
+
async def get_node(
|
|
162
|
+
node_id: str,
|
|
163
|
+
request: Request,
|
|
164
|
+
integration: Optional[str] = None,
|
|
165
|
+
organization: dict = Depends(get_current_organization),
|
|
166
|
+
):
|
|
167
|
+
"""Get a specific node by its ID."""
|
|
168
|
+
query_params = {}
|
|
169
|
+
if integration:
|
|
170
|
+
query_params["integration"] = integration
|
|
171
|
+
|
|
172
|
+
return await proxy_graph_request(
|
|
173
|
+
request=request,
|
|
174
|
+
path=f"/api/v1/graph/nodes/{node_id}",
|
|
175
|
+
method="GET",
|
|
176
|
+
query_params=query_params,
|
|
177
|
+
organization=organization,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@router.get("/api/v1/graph/nodes/{node_id}/relationships")
|
|
182
|
+
async def get_relationships(
|
|
183
|
+
node_id: str,
|
|
184
|
+
request: Request,
|
|
185
|
+
direction: str = "both",
|
|
186
|
+
relationship_type: Optional[str] = None,
|
|
187
|
+
integration: Optional[str] = None,
|
|
188
|
+
skip: int = 0,
|
|
189
|
+
limit: int = 100,
|
|
190
|
+
organization: dict = Depends(get_current_organization),
|
|
191
|
+
):
|
|
192
|
+
"""Get relationships for a specific node."""
|
|
193
|
+
query_params = {
|
|
194
|
+
"direction": direction,
|
|
195
|
+
"skip": skip,
|
|
196
|
+
"limit": limit,
|
|
197
|
+
}
|
|
198
|
+
if relationship_type:
|
|
199
|
+
query_params["relationship_type"] = relationship_type
|
|
200
|
+
if integration:
|
|
201
|
+
query_params["integration"] = integration
|
|
202
|
+
|
|
203
|
+
return await proxy_graph_request(
|
|
204
|
+
request=request,
|
|
205
|
+
path=f"/api/v1/graph/nodes/{node_id}/relationships",
|
|
206
|
+
method="GET",
|
|
207
|
+
query_params=query_params,
|
|
208
|
+
organization=organization,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@router.post("/api/v1/graph/subgraph")
|
|
213
|
+
async def get_subgraph(
|
|
214
|
+
request: Request,
|
|
215
|
+
body: Dict[str, Any],
|
|
216
|
+
integration: Optional[str] = None,
|
|
217
|
+
organization: dict = Depends(get_current_organization),
|
|
218
|
+
):
|
|
219
|
+
"""
|
|
220
|
+
Get a subgraph starting from a node.
|
|
221
|
+
|
|
222
|
+
Body should contain SubgraphRequest:
|
|
223
|
+
- node_id: Starting node ID
|
|
224
|
+
- depth: Traversal depth (1-5)
|
|
225
|
+
- relationship_types: Optional list of relationship types to follow
|
|
226
|
+
"""
|
|
227
|
+
query_params = {}
|
|
228
|
+
if integration:
|
|
229
|
+
query_params["integration"] = integration
|
|
230
|
+
|
|
231
|
+
return await proxy_graph_request(
|
|
232
|
+
request=request,
|
|
233
|
+
path="/api/v1/graph/subgraph",
|
|
234
|
+
method="POST",
|
|
235
|
+
query_params=query_params,
|
|
236
|
+
body=body,
|
|
237
|
+
organization=organization,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@router.post("/api/v1/graph/nodes/search/text")
|
|
242
|
+
async def search_by_text(
|
|
243
|
+
request: Request,
|
|
244
|
+
body: Dict[str, Any],
|
|
245
|
+
integration: Optional[str] = None,
|
|
246
|
+
skip: int = 0,
|
|
247
|
+
limit: int = 100,
|
|
248
|
+
organization: dict = Depends(get_current_organization),
|
|
249
|
+
):
|
|
250
|
+
"""
|
|
251
|
+
Search nodes by text pattern in a property.
|
|
252
|
+
|
|
253
|
+
Body should contain TextSearchRequest:
|
|
254
|
+
- property_name: Property name to search in
|
|
255
|
+
- search_text: Text to search for
|
|
256
|
+
- label: Optional node label to filter by
|
|
257
|
+
"""
|
|
258
|
+
query_params = {"skip": skip, "limit": limit}
|
|
259
|
+
if integration:
|
|
260
|
+
query_params["integration"] = integration
|
|
261
|
+
|
|
262
|
+
return await proxy_graph_request(
|
|
263
|
+
request=request,
|
|
264
|
+
path="/api/v1/graph/nodes/search/text",
|
|
265
|
+
method="POST",
|
|
266
|
+
query_params=query_params,
|
|
267
|
+
body=body,
|
|
268
|
+
organization=organization,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@router.get("/api/v1/graph/nodes")
|
|
273
|
+
async def get_all_nodes(
|
|
274
|
+
request: Request,
|
|
275
|
+
integration: Optional[str] = None,
|
|
276
|
+
skip: int = 0,
|
|
277
|
+
limit: int = 100,
|
|
278
|
+
organization: dict = Depends(get_current_organization),
|
|
279
|
+
):
|
|
280
|
+
"""
|
|
281
|
+
Get all nodes in the organization.
|
|
282
|
+
|
|
283
|
+
Optionally filter by integration label to get nodes from a specific integration.
|
|
284
|
+
"""
|
|
285
|
+
query_params = {"skip": skip, "limit": limit}
|
|
286
|
+
if integration:
|
|
287
|
+
query_params["integration"] = integration
|
|
288
|
+
|
|
289
|
+
return await proxy_graph_request(
|
|
290
|
+
request=request,
|
|
291
|
+
path="/api/v1/graph/nodes",
|
|
292
|
+
method="GET",
|
|
293
|
+
query_params=query_params,
|
|
294
|
+
organization=organization,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@router.get("/api/v1/graph/labels")
|
|
299
|
+
async def get_labels(
|
|
300
|
+
request: Request,
|
|
301
|
+
integration: Optional[str] = None,
|
|
302
|
+
skip: int = 0,
|
|
303
|
+
limit: int = 100,
|
|
304
|
+
organization: dict = Depends(get_current_organization),
|
|
305
|
+
):
|
|
306
|
+
"""Get all node labels in the context graph."""
|
|
307
|
+
query_params = {"skip": skip, "limit": limit}
|
|
308
|
+
if integration:
|
|
309
|
+
query_params["integration"] = integration
|
|
310
|
+
|
|
311
|
+
return await proxy_graph_request(
|
|
312
|
+
request=request,
|
|
313
|
+
path="/api/v1/graph/labels",
|
|
314
|
+
method="GET",
|
|
315
|
+
query_params=query_params,
|
|
316
|
+
organization=organization,
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
@router.get("/api/v1/graph/relationship-types")
|
|
321
|
+
async def get_relationship_types(
|
|
322
|
+
request: Request,
|
|
323
|
+
integration: Optional[str] = None,
|
|
324
|
+
skip: int = 0,
|
|
325
|
+
limit: int = 100,
|
|
326
|
+
organization: dict = Depends(get_current_organization),
|
|
327
|
+
):
|
|
328
|
+
"""Get all relationship types in the context graph."""
|
|
329
|
+
query_params = {"skip": skip, "limit": limit}
|
|
330
|
+
if integration:
|
|
331
|
+
query_params["integration"] = integration
|
|
332
|
+
|
|
333
|
+
return await proxy_graph_request(
|
|
334
|
+
request=request,
|
|
335
|
+
path="/api/v1/graph/relationship-types",
|
|
336
|
+
method="GET",
|
|
337
|
+
query_params=query_params,
|
|
338
|
+
organization=organization,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@router.get("/api/v1/graph/stats")
|
|
343
|
+
async def get_stats(
|
|
344
|
+
request: Request,
|
|
345
|
+
integration: Optional[str] = None,
|
|
346
|
+
skip: int = 0,
|
|
347
|
+
limit: int = 100,
|
|
348
|
+
organization: dict = Depends(get_current_organization),
|
|
349
|
+
):
|
|
350
|
+
"""Get statistics about the context graph."""
|
|
351
|
+
query_params = {"skip": skip, "limit": limit}
|
|
352
|
+
if integration:
|
|
353
|
+
query_params["integration"] = integration
|
|
354
|
+
|
|
355
|
+
return await proxy_graph_request(
|
|
356
|
+
request=request,
|
|
357
|
+
path="/api/v1/graph/stats",
|
|
358
|
+
method="GET",
|
|
359
|
+
query_params=query_params,
|
|
360
|
+
organization=organization,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
@router.post("/api/v1/graph/query")
|
|
365
|
+
async def execute_query(
|
|
366
|
+
request: Request,
|
|
367
|
+
body: Dict[str, Any],
|
|
368
|
+
organization: dict = Depends(get_current_organization),
|
|
369
|
+
):
|
|
370
|
+
"""
|
|
371
|
+
Execute a custom Cypher query (read-only).
|
|
372
|
+
|
|
373
|
+
The query will be automatically scoped to your organization's data.
|
|
374
|
+
All node patterns will have the organization label injected.
|
|
375
|
+
|
|
376
|
+
Body should contain CustomQueryRequest:
|
|
377
|
+
- query: Cypher query to execute (read-only)
|
|
378
|
+
"""
|
|
379
|
+
return await proxy_graph_request(
|
|
380
|
+
request=request,
|
|
381
|
+
path="/api/v1/graph/query",
|
|
382
|
+
method="POST",
|
|
383
|
+
body=body,
|
|
384
|
+
organization=organization,
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
@router.get("/api/v1/graph/integrations")
|
|
389
|
+
async def get_integrations(
|
|
390
|
+
request: Request,
|
|
391
|
+
skip: int = 0,
|
|
392
|
+
limit: int = 100,
|
|
393
|
+
organization: dict = Depends(get_current_organization),
|
|
394
|
+
):
|
|
395
|
+
"""Get all available integrations for the organization."""
|
|
396
|
+
query_params = {"skip": skip, "limit": limit}
|
|
397
|
+
|
|
398
|
+
return await proxy_graph_request(
|
|
399
|
+
request=request,
|
|
400
|
+
path="/api/v1/graph/integrations",
|
|
401
|
+
method="GET",
|
|
402
|
+
query_params=query_params,
|
|
403
|
+
organization=organization,
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
# ============================================================================
|
|
408
|
+
# Semantic Search Endpoint
|
|
409
|
+
# ============================================================================
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
@router.post("/graph/search")
|
|
413
|
+
async def semantic_search(
|
|
414
|
+
request: Request,
|
|
415
|
+
body: Dict[str, Any],
|
|
416
|
+
organization: dict = Depends(get_current_organization),
|
|
417
|
+
):
|
|
418
|
+
"""
|
|
419
|
+
Semantic search across knowledge graph.
|
|
420
|
+
|
|
421
|
+
Performs vector similarity search over processed knowledge to find
|
|
422
|
+
relevant information based on natural language queries.
|
|
423
|
+
|
|
424
|
+
Body should contain:
|
|
425
|
+
- query: Natural language question or keywords (required)
|
|
426
|
+
- limit: Maximum results (1-100, default 10)
|
|
427
|
+
- filters: Optional filters (dataset_ids, etc.)
|
|
428
|
+
- search_type: Search strategy (GRAPH_COMPLETION, CHUNKS, RAG_COMPLETION, TEMPORAL, FEEDBACK)
|
|
429
|
+
"""
|
|
430
|
+
return await proxy_graph_request(
|
|
431
|
+
request=request,
|
|
432
|
+
path="/api/v1/graph/search",
|
|
433
|
+
method="POST",
|
|
434
|
+
body=body,
|
|
435
|
+
organization=organization,
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
# ============================================================================
|
|
440
|
+
# Intelligent Search Endpoints
|
|
441
|
+
# ============================================================================
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
@router.post("/intelligent-search")
|
|
445
|
+
async def intelligent_search(
|
|
446
|
+
request: Request,
|
|
447
|
+
body: Dict[str, Any],
|
|
448
|
+
organization: dict = Depends(get_current_organization),
|
|
449
|
+
):
|
|
450
|
+
"""
|
|
451
|
+
Perform AI-powered intelligent graph search using natural language.
|
|
452
|
+
|
|
453
|
+
Body should contain IntelligentSearchRequest:
|
|
454
|
+
- keywords: Natural language query (required)
|
|
455
|
+
- max_turns: Maximum agent turns (1-20, default: 5)
|
|
456
|
+
- system_prompt: Optional system prompt
|
|
457
|
+
- additional_context: Optional additional context
|
|
458
|
+
- model: LiteLLM model name (default: kubiya/claude-sonnet-4)
|
|
459
|
+
- temperature: Model temperature (0.0-2.0, default: 0.7)
|
|
460
|
+
- integration: Filter by integration
|
|
461
|
+
- label_filter: Filter by node label
|
|
462
|
+
- enable_semantic_search: Enable semantic search
|
|
463
|
+
- enable_cypher_queries: Enable custom Cypher queries
|
|
464
|
+
- strategy: Agent strategy (claude_sdk or agno)
|
|
465
|
+
- session_id: Session ID for multi-turn conversations
|
|
466
|
+
"""
|
|
467
|
+
return await proxy_graph_request(
|
|
468
|
+
request=request,
|
|
469
|
+
path="/api/v1/graph/intelligent-search",
|
|
470
|
+
method="POST",
|
|
471
|
+
body=body,
|
|
472
|
+
organization=organization,
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
@router.post("/intelligent-search/stream")
|
|
477
|
+
async def intelligent_search_stream(
|
|
478
|
+
request: Request,
|
|
479
|
+
body: Dict[str, Any],
|
|
480
|
+
organization: dict = Depends(get_current_organization),
|
|
481
|
+
):
|
|
482
|
+
"""
|
|
483
|
+
Perform streaming AI-powered intelligent graph search with real-time updates.
|
|
484
|
+
|
|
485
|
+
Returns Server-Sent Events (SSE) stream with:
|
|
486
|
+
- session: Session ID
|
|
487
|
+
- progress: Progress updates with percentage
|
|
488
|
+
- tool_call: Tool invocations
|
|
489
|
+
- partial_answer: Incremental answer text
|
|
490
|
+
- complete: Final results
|
|
491
|
+
- error: Error messages
|
|
492
|
+
"""
|
|
493
|
+
# For streaming, we need to handle SSE differently
|
|
494
|
+
# Use the proxy but preserve streaming response
|
|
495
|
+
try:
|
|
496
|
+
token = request.state.kubiya_token
|
|
497
|
+
auth_type = getattr(request.state, "kubiya_auth_type", "Bearer")
|
|
498
|
+
org_id = organization["id"] if organization else None
|
|
499
|
+
|
|
500
|
+
headers = {
|
|
501
|
+
"Authorization": f"{auth_type} {token}",
|
|
502
|
+
"Accept": "text/event-stream",
|
|
503
|
+
"Content-Type": "application/json",
|
|
504
|
+
"X-Kubiya-Client": "agent-control-plane",
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if org_id:
|
|
508
|
+
headers["X-Organization-ID"] = org_id
|
|
509
|
+
|
|
510
|
+
base_url = settings.context_graph_api_base.rstrip("/")
|
|
511
|
+
full_url = f"{base_url}/api/v1/graph/intelligent-search/stream"
|
|
512
|
+
|
|
513
|
+
async with httpx.AsyncClient(timeout=settings.context_graph_api_timeout) as client:
|
|
514
|
+
response = await client.post(full_url, headers=headers, json=body)
|
|
515
|
+
|
|
516
|
+
logger.info(
|
|
517
|
+
"context_graph_streaming_request",
|
|
518
|
+
org_id=org_id,
|
|
519
|
+
path="/api/v1/graph/intelligent-search/stream",
|
|
520
|
+
status=response.status_code,
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
# Return streaming response
|
|
524
|
+
return Response(
|
|
525
|
+
content=response.content,
|
|
526
|
+
status_code=response.status_code,
|
|
527
|
+
headers=dict(response.headers),
|
|
528
|
+
media_type="text/event-stream",
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
except httpx.TimeoutException:
|
|
532
|
+
logger.error("context_graph_stream_timeout")
|
|
533
|
+
raise HTTPException(status_code=504, detail="Streaming search timed out")
|
|
534
|
+
except httpx.RequestError as e:
|
|
535
|
+
logger.error("context_graph_stream_error", error=str(e))
|
|
536
|
+
raise HTTPException(status_code=502, detail=f"Failed to connect: {str(e)}")
|
|
537
|
+
except Exception as e:
|
|
538
|
+
logger.error("context_graph_stream_unexpected_error", error=str(e))
|
|
539
|
+
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
@router.get("/intelligent-search/health")
|
|
543
|
+
async def intelligent_search_health(
|
|
544
|
+
request: Request,
|
|
545
|
+
organization: dict = Depends(get_current_organization),
|
|
546
|
+
):
|
|
547
|
+
"""
|
|
548
|
+
Check health status of intelligent search service.
|
|
549
|
+
|
|
550
|
+
Returns:
|
|
551
|
+
- status: "healthy", "degraded", or "unhealthy"
|
|
552
|
+
- strategies: Available agent strategies
|
|
553
|
+
- configuration: Service configuration
|
|
554
|
+
- message: Status message
|
|
555
|
+
"""
|
|
556
|
+
return await proxy_graph_request(
|
|
557
|
+
request=request,
|
|
558
|
+
path="/api/v1/graph/intelligent-search/health",
|
|
559
|
+
method="GET",
|
|
560
|
+
organization=organization,
|
|
561
|
+
)
|