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,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Execution streaming components.
|
|
3
|
+
|
|
4
|
+
This package contains modular components for handling streaming execution data,
|
|
5
|
+
extracted from the monolithic executions.py router.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Import main router and utilities from parent executions.py
|
|
9
|
+
# This allows: from control_plane_api.app.routers.executions import router, validate_job_exists
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
# Import from the sibling executions.py file (not this package)
|
|
14
|
+
_parent_dir = Path(__file__).parent.parent
|
|
15
|
+
_executions_module_path = _parent_dir / "executions.py"
|
|
16
|
+
|
|
17
|
+
# We need to import from ../executions.py, not this package
|
|
18
|
+
# Python's import system sees this directory first, so we explicitly import the file
|
|
19
|
+
import importlib.util
|
|
20
|
+
spec = importlib.util.spec_from_file_location("_executions_module", _executions_module_path)
|
|
21
|
+
_executions_module = importlib.util.module_from_spec(spec)
|
|
22
|
+
spec.loader.exec_module(_executions_module)
|
|
23
|
+
|
|
24
|
+
# Re-export the main router and utilities
|
|
25
|
+
router = _executions_module.router
|
|
26
|
+
validate_job_exists = _executions_module.validate_job_exists
|
|
27
|
+
|
|
28
|
+
__all__ = ["router", "validate_job_exists"]
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Clean streaming router using ExecutionStreamer architecture.
|
|
3
|
+
|
|
4
|
+
This module provides a clean FastAPI router for execution streaming
|
|
5
|
+
that replaces the monolithic ~2,100 line inline implementation with
|
|
6
|
+
the modular ExecutionStreamer class.
|
|
7
|
+
|
|
8
|
+
Architecture:
|
|
9
|
+
- Immediate connection acknowledgment (<50ms)
|
|
10
|
+
- Progressive historical message loading
|
|
11
|
+
- Live event streaming with gap recovery
|
|
12
|
+
- Graceful degradation when services unavailable
|
|
13
|
+
- Last-Event-ID resumption support
|
|
14
|
+
|
|
15
|
+
The endpoint uses ExecutionStreamer which orchestrates:
|
|
16
|
+
- HistoryLoader: Database message loading with Temporal fallback
|
|
17
|
+
- LiveEventSource: Redis event streaming with workflow state polling
|
|
18
|
+
- MessageDeduplicator: Deduplication across history and live phases
|
|
19
|
+
- EventBuffer: Gap detection and replay for reconnection
|
|
20
|
+
- EventFormatter: Consistent SSE formatting
|
|
21
|
+
- WorkerHealthChecker: Graceful degradation mode detection
|
|
22
|
+
|
|
23
|
+
Test Strategy:
|
|
24
|
+
- Integration test with real execution IDs
|
|
25
|
+
- Test all event types are emitted correctly
|
|
26
|
+
- Test Last-Event-ID resumption works
|
|
27
|
+
- Test graceful degradation modes
|
|
28
|
+
- Test backward compatibility with existing clients
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
import asyncio
|
|
32
|
+
import uuid as uuid_module
|
|
33
|
+
from typing import Optional
|
|
34
|
+
|
|
35
|
+
import structlog
|
|
36
|
+
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
37
|
+
from fastapi.responses import StreamingResponse
|
|
38
|
+
from sqlalchemy.orm import Session
|
|
39
|
+
|
|
40
|
+
from control_plane_api.app.database import get_db
|
|
41
|
+
from control_plane_api.app.lib.redis_client import get_redis_client
|
|
42
|
+
from control_plane_api.app.lib.temporal_client import get_temporal_client
|
|
43
|
+
from control_plane_api.app.middleware.auth import get_current_organization
|
|
44
|
+
from control_plane_api.app.models.execution import Execution
|
|
45
|
+
|
|
46
|
+
from .streaming import ExecutionStreamer
|
|
47
|
+
from .services.worker_health import WorkerHealthChecker
|
|
48
|
+
|
|
49
|
+
logger = structlog.get_logger(__name__)
|
|
50
|
+
|
|
51
|
+
router = APIRouter()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@router.get("/{execution_id}/stream")
|
|
55
|
+
async def stream_execution(
|
|
56
|
+
execution_id: str,
|
|
57
|
+
request: Request,
|
|
58
|
+
last_event_id: Optional[str] = None,
|
|
59
|
+
organization: dict = Depends(get_current_organization),
|
|
60
|
+
db: Session = Depends(get_db),
|
|
61
|
+
):
|
|
62
|
+
"""
|
|
63
|
+
Stream execution updates using Server-Sent Events (SSE).
|
|
64
|
+
|
|
65
|
+
This endpoint provides real-time execution updates by combining:
|
|
66
|
+
1. Historical messages from database (last 200 messages)
|
|
67
|
+
2. Live events from Redis (sub-second latency)
|
|
68
|
+
3. Workflow state from Temporal (200ms polling)
|
|
69
|
+
|
|
70
|
+
The endpoint supports:
|
|
71
|
+
- Progressive history loading (no blocking on full history)
|
|
72
|
+
- Last-Event-ID resumption for reconnection
|
|
73
|
+
- Gap detection and notification
|
|
74
|
+
- Graceful degradation when services unavailable
|
|
75
|
+
- Backward compatible with existing clients
|
|
76
|
+
|
|
77
|
+
Architecture:
|
|
78
|
+
This endpoint uses the ExecutionStreamer class which orchestrates
|
|
79
|
+
all phases of streaming:
|
|
80
|
+
1. Immediate connection (<50ms)
|
|
81
|
+
2. History loading (progressive, one message at a time)
|
|
82
|
+
3. History completion notification
|
|
83
|
+
4. Live event streaming (until workflow completes or timeout)
|
|
84
|
+
|
|
85
|
+
Gap Recovery:
|
|
86
|
+
- Supports Last-Event-ID pattern for reconnection
|
|
87
|
+
- Client sends last_event_id query param or Last-Event-ID header
|
|
88
|
+
- Server resumes from that point or detects gaps
|
|
89
|
+
- Buffered events replayed if available
|
|
90
|
+
- Client notified if gap unrecoverable
|
|
91
|
+
|
|
92
|
+
SSE Event Types:
|
|
93
|
+
- connected: Initial connection acknowledgment
|
|
94
|
+
- message: Chat message (history or live)
|
|
95
|
+
- message_chunk: Streaming message chunk
|
|
96
|
+
- member_message_chunk: Team member message chunk
|
|
97
|
+
- history_complete: All historical messages sent
|
|
98
|
+
- status: Execution status update
|
|
99
|
+
- tool_started: Tool execution started
|
|
100
|
+
- tool_completed: Tool execution completed
|
|
101
|
+
- degraded: Service degradation notification
|
|
102
|
+
- recovered: Service recovery notification
|
|
103
|
+
- gap_detected: Gap in event stream detected
|
|
104
|
+
- error: Error occurred
|
|
105
|
+
- keepalive: Connection keepalive (comment)
|
|
106
|
+
|
|
107
|
+
SSE Format:
|
|
108
|
+
- id: {execution_id}_{counter}_{timestamp_micros}
|
|
109
|
+
- event: {event_type}
|
|
110
|
+
- data: {json object}
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
execution_id: Execution ID to stream
|
|
114
|
+
request: FastAPI request object (for headers)
|
|
115
|
+
last_event_id: Last event ID received by client (for resumption)
|
|
116
|
+
organization: Authenticated organization (injected by auth middleware)
|
|
117
|
+
db: Database session (injected by dependency)
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
StreamingResponse with text/event-stream content
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
HTTPException 404: Execution not found or not authorized
|
|
124
|
+
HTTPException 500: Critical initialization error
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
# ========== AUTHENTICATION & AUTHORIZATION ==========
|
|
128
|
+
# Already handled by get_current_organization dependency
|
|
129
|
+
logger.info(
|
|
130
|
+
"stream_request_received",
|
|
131
|
+
execution_id=execution_id[:8],
|
|
132
|
+
organization_id=organization["id"][:8],
|
|
133
|
+
has_last_event_id=bool(last_event_id or request.headers.get("Last-Event-ID")),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# ========== GET EXECUTION TYPE FROM DATABASE ==========
|
|
137
|
+
# This determines the workflow ID format:
|
|
138
|
+
# - TEAM: "team-execution-{id}"
|
|
139
|
+
# - AGENT: "agent-execution-{id}" (default)
|
|
140
|
+
try:
|
|
141
|
+
execution_record = db.query(Execution).filter(
|
|
142
|
+
Execution.id == uuid_module.UUID(execution_id),
|
|
143
|
+
Execution.organization_id == organization["id"]
|
|
144
|
+
).first()
|
|
145
|
+
|
|
146
|
+
if not execution_record:
|
|
147
|
+
raise HTTPException(
|
|
148
|
+
status_code=404,
|
|
149
|
+
detail=f"Execution {execution_id} not found or not authorized"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
execution_type = execution_record.execution_type or "AGENT"
|
|
153
|
+
|
|
154
|
+
logger.info(
|
|
155
|
+
"execution_type_determined",
|
|
156
|
+
execution_id=execution_id[:8],
|
|
157
|
+
execution_type=execution_type,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
except HTTPException:
|
|
161
|
+
raise
|
|
162
|
+
except Exception as e:
|
|
163
|
+
logger.error(
|
|
164
|
+
"failed_to_query_execution",
|
|
165
|
+
execution_id=execution_id[:8],
|
|
166
|
+
error=str(e),
|
|
167
|
+
error_type=type(e).__name__,
|
|
168
|
+
)
|
|
169
|
+
raise HTTPException(
|
|
170
|
+
status_code=500,
|
|
171
|
+
detail=f"Failed to query execution: {str(e)}"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# ========== INITIALIZE INFRASTRUCTURE CLIENTS ==========
|
|
175
|
+
# Get clients with graceful degradation support
|
|
176
|
+
# - Temporal client: 2s timeout to fail fast when worker down
|
|
177
|
+
# - Redis client: Can be None if not configured
|
|
178
|
+
# - Database session: Already available from dependency
|
|
179
|
+
|
|
180
|
+
# Redis client (optional, graceful degradation if None)
|
|
181
|
+
redis_client = get_redis_client()
|
|
182
|
+
if not redis_client:
|
|
183
|
+
logger.warning(
|
|
184
|
+
"redis_not_configured",
|
|
185
|
+
execution_id=execution_id[:8],
|
|
186
|
+
note="Live streaming will be unavailable"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Temporal client with fast timeout (optional, graceful degradation)
|
|
190
|
+
temporal_client = None
|
|
191
|
+
try:
|
|
192
|
+
temporal_client = await asyncio.wait_for(
|
|
193
|
+
get_temporal_client(),
|
|
194
|
+
timeout=2.0 # Fail fast - don't block streaming
|
|
195
|
+
)
|
|
196
|
+
logger.info(
|
|
197
|
+
"temporal_client_connected",
|
|
198
|
+
execution_id=execution_id[:8],
|
|
199
|
+
)
|
|
200
|
+
except asyncio.TimeoutError:
|
|
201
|
+
logger.warning(
|
|
202
|
+
"temporal_connection_timeout",
|
|
203
|
+
execution_id=execution_id[:8],
|
|
204
|
+
timeout_seconds=2.0,
|
|
205
|
+
note="Workflow queries will be unavailable"
|
|
206
|
+
)
|
|
207
|
+
except Exception as temporal_error:
|
|
208
|
+
logger.warning(
|
|
209
|
+
"temporal_connection_failed",
|
|
210
|
+
execution_id=execution_id[:8],
|
|
211
|
+
error=str(temporal_error),
|
|
212
|
+
error_type=type(temporal_error).__name__,
|
|
213
|
+
note="Continuing without Temporal support"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
# ========== PARSE LAST-EVENT-ID ==========
|
|
217
|
+
# Check both query param and header (EventSource sets header automatically)
|
|
218
|
+
parsed_last_event_id = last_event_id or request.headers.get("Last-Event-ID")
|
|
219
|
+
|
|
220
|
+
if parsed_last_event_id:
|
|
221
|
+
logger.info(
|
|
222
|
+
"resumption_requested",
|
|
223
|
+
execution_id=execution_id[:8],
|
|
224
|
+
last_event_id=parsed_last_event_id,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# ========== CREATE WORKER HEALTH CHECKER ==========
|
|
228
|
+
# This determines degradation mode based on service availability
|
|
229
|
+
health_checker = WorkerHealthChecker(
|
|
230
|
+
temporal_client=temporal_client,
|
|
231
|
+
redis_client=redis_client,
|
|
232
|
+
db_session=db,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# ========== INSTANTIATE EXECUTION STREAMER ==========
|
|
236
|
+
# This orchestrates all phases of streaming:
|
|
237
|
+
# 1. Immediate connection
|
|
238
|
+
# 2. Resumption (if Last-Event-ID provided)
|
|
239
|
+
# 3. Historical message loading
|
|
240
|
+
# 4. History completion notification
|
|
241
|
+
# 5. Live event streaming
|
|
242
|
+
try:
|
|
243
|
+
streamer = ExecutionStreamer(
|
|
244
|
+
execution_id=execution_id,
|
|
245
|
+
organization_id=organization["id"],
|
|
246
|
+
db_session=db,
|
|
247
|
+
redis_client=redis_client,
|
|
248
|
+
temporal_client=temporal_client,
|
|
249
|
+
last_event_id=parsed_last_event_id,
|
|
250
|
+
timeout_seconds=0, # 0 = no timeout, stream until task completes
|
|
251
|
+
execution_type=execution_type,
|
|
252
|
+
health_checker=health_checker,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
logger.info(
|
|
256
|
+
"streamer_initialized",
|
|
257
|
+
execution_id=execution_id[:8],
|
|
258
|
+
execution_type=execution_type,
|
|
259
|
+
has_redis=bool(redis_client),
|
|
260
|
+
has_temporal=bool(temporal_client),
|
|
261
|
+
has_last_event_id=bool(parsed_last_event_id),
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
except Exception as e:
|
|
265
|
+
logger.error(
|
|
266
|
+
"failed_to_initialize_streamer",
|
|
267
|
+
execution_id=execution_id[:8],
|
|
268
|
+
error=str(e),
|
|
269
|
+
error_type=type(e).__name__,
|
|
270
|
+
)
|
|
271
|
+
raise HTTPException(
|
|
272
|
+
status_code=500,
|
|
273
|
+
detail=f"Failed to initialize streaming: {str(e)}"
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# ========== RETURN STREAMING RESPONSE ==========
|
|
277
|
+
# StreamingResponse will call streamer.stream() which yields SSE events
|
|
278
|
+
return StreamingResponse(
|
|
279
|
+
streamer.stream(),
|
|
280
|
+
media_type="text/event-stream",
|
|
281
|
+
headers={
|
|
282
|
+
"Cache-Control": "no-cache",
|
|
283
|
+
"Connection": "keep-alive",
|
|
284
|
+
"X-Accel-Buffering": "no", # Disable nginx buffering for real-time
|
|
285
|
+
}
|
|
286
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Execution services package
|
|
2
|
+
|
|
3
|
+
This package contains service classes for execution-related functionality:
|
|
4
|
+
- worker_health: Worker and service health checking with graceful degradation
|
|
5
|
+
- status_service: Cached workflow status queries to reduce Temporal API load
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from control_plane_api.app.routers.executions.services.worker_health import (
|
|
9
|
+
WorkerHealthChecker,
|
|
10
|
+
DegradationMode,
|
|
11
|
+
CAPABILITIES,
|
|
12
|
+
)
|
|
13
|
+
from control_plane_api.app.routers.executions.services.status_service import (
|
|
14
|
+
StatusService,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"WorkerHealthChecker",
|
|
19
|
+
"DegradationMode",
|
|
20
|
+
"CAPABILITIES",
|
|
21
|
+
"StatusService",
|
|
22
|
+
]
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Demo script for WorkerHealthChecker service
|
|
3
|
+
|
|
4
|
+
This script demonstrates the WorkerHealthChecker service in action.
|
|
5
|
+
It shows health checks, degradation modes, and capabilities.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
cd /Users/shaked/projects/agent-control-plane/control_plane_api/app/routers/executions/services
|
|
9
|
+
python demo_worker_health.py
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
# Add parent directory to path for imports
|
|
17
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
18
|
+
|
|
19
|
+
from worker_health import (
|
|
20
|
+
WorkerHealthChecker,
|
|
21
|
+
DegradationMode,
|
|
22
|
+
CAPABILITIES,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def print_section(title: str):
|
|
27
|
+
"""Print a section header."""
|
|
28
|
+
print(f"\n{'=' * 60}")
|
|
29
|
+
print(f" {title}")
|
|
30
|
+
print(f"{'=' * 60}\n")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def demo_no_services():
|
|
34
|
+
"""Demo: No services available."""
|
|
35
|
+
print_section("Demo 1: No Services Available")
|
|
36
|
+
|
|
37
|
+
checker = WorkerHealthChecker(
|
|
38
|
+
temporal_client=None,
|
|
39
|
+
redis_client=None,
|
|
40
|
+
db_session=None,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
print("Checking service health...")
|
|
44
|
+
results = await checker.check_all()
|
|
45
|
+
print(f" Temporal: {'✓' if results['temporal'] else '✗'}")
|
|
46
|
+
print(f" Redis: {'✓' if results['redis'] else '✗'}")
|
|
47
|
+
print(f" Database: {'✓' if results['database'] else '✗'}")
|
|
48
|
+
|
|
49
|
+
print("\nDetermining degradation mode...")
|
|
50
|
+
mode = await checker.get_degradation_mode()
|
|
51
|
+
print(f" Mode: {mode.value}")
|
|
52
|
+
|
|
53
|
+
print("\nAvailable capabilities:")
|
|
54
|
+
capabilities = checker.get_capabilities(mode)
|
|
55
|
+
if capabilities:
|
|
56
|
+
for cap in capabilities:
|
|
57
|
+
print(f" - {cap}")
|
|
58
|
+
else:
|
|
59
|
+
print(" (none)")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def demo_cache_behavior():
|
|
63
|
+
"""Demo: Cache behavior."""
|
|
64
|
+
print_section("Demo 2: Health Check Caching")
|
|
65
|
+
|
|
66
|
+
checker = WorkerHealthChecker(
|
|
67
|
+
temporal_client=None,
|
|
68
|
+
redis_client=None,
|
|
69
|
+
db_session=None,
|
|
70
|
+
cache_ttl=5 # 5 second cache
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
print("First health check (will hit services)...")
|
|
74
|
+
start = asyncio.get_event_loop().time()
|
|
75
|
+
await checker.check_all()
|
|
76
|
+
duration1 = asyncio.get_event_loop().time() - start
|
|
77
|
+
print(f" Duration: {duration1:.3f}s")
|
|
78
|
+
|
|
79
|
+
print("\nSecond health check (should use cache)...")
|
|
80
|
+
start = asyncio.get_event_loop().time()
|
|
81
|
+
await checker.check_all()
|
|
82
|
+
duration2 = asyncio.get_event_loop().time() - start
|
|
83
|
+
print(f" Duration: {duration2:.3f}s")
|
|
84
|
+
|
|
85
|
+
if duration2 < duration1:
|
|
86
|
+
print(f" ✓ Cache is working! Second check was faster.")
|
|
87
|
+
else:
|
|
88
|
+
print(f" ℹ Both checks were similar (expected if services are None)")
|
|
89
|
+
|
|
90
|
+
print("\nClearing cache...")
|
|
91
|
+
checker.clear_cache()
|
|
92
|
+
print(" ✓ Cache cleared")
|
|
93
|
+
|
|
94
|
+
print("\nThird health check (should hit services again)...")
|
|
95
|
+
start = asyncio.get_event_loop().time()
|
|
96
|
+
await checker.check_all()
|
|
97
|
+
duration3 = asyncio.get_event_loop().time() - start
|
|
98
|
+
print(f" Duration: {duration3:.3f}s")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def demo_all_degradation_modes():
|
|
102
|
+
"""Demo: All degradation modes."""
|
|
103
|
+
print_section("Demo 3: All Degradation Modes")
|
|
104
|
+
|
|
105
|
+
print("Degradation mode capabilities:\n")
|
|
106
|
+
|
|
107
|
+
for mode in DegradationMode:
|
|
108
|
+
capabilities = CAPABILITIES.get(mode, [])
|
|
109
|
+
print(f"{mode.value.upper()}")
|
|
110
|
+
print(f" Capabilities: {', '.join(capabilities) if capabilities else 'none'}")
|
|
111
|
+
print()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async def demo_timeout_behavior():
|
|
115
|
+
"""Demo: Timeout behavior simulation."""
|
|
116
|
+
print_section("Demo 4: Timeout Behavior")
|
|
117
|
+
|
|
118
|
+
print("Health check timeouts:")
|
|
119
|
+
print(f" Temporal: {WorkerHealthChecker.TEMPORAL_TIMEOUT}s")
|
|
120
|
+
print(f" Redis: {WorkerHealthChecker.REDIS_TIMEOUT}s")
|
|
121
|
+
print(f" Database: {WorkerHealthChecker.DATABASE_TIMEOUT}s")
|
|
122
|
+
|
|
123
|
+
print("\nThese timeouts ensure the API remains responsive even when")
|
|
124
|
+
print("services are down or slow. Without timeouts, a client request")
|
|
125
|
+
print("could hang for 30+ seconds waiting for services to fail.")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
async def main():
|
|
129
|
+
"""Run all demos."""
|
|
130
|
+
print("\n" + "=" * 60)
|
|
131
|
+
print(" WorkerHealthChecker Service Demo")
|
|
132
|
+
print("=" * 60)
|
|
133
|
+
print("\nThis demo shows how the WorkerHealthChecker service works.")
|
|
134
|
+
print("It demonstrates health checks, degradation modes, and caching.")
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
await demo_no_services()
|
|
138
|
+
await demo_cache_behavior()
|
|
139
|
+
await demo_all_degradation_modes()
|
|
140
|
+
await demo_timeout_behavior()
|
|
141
|
+
|
|
142
|
+
print_section("Demo Complete")
|
|
143
|
+
print("✓ All demos completed successfully")
|
|
144
|
+
print("\nFor integration examples, see:")
|
|
145
|
+
print(" - USAGE_EXAMPLE.md")
|
|
146
|
+
print(" - test_worker_health.py")
|
|
147
|
+
print()
|
|
148
|
+
|
|
149
|
+
except Exception as e:
|
|
150
|
+
print(f"\n✗ Demo failed: {e}")
|
|
151
|
+
import traceback
|
|
152
|
+
traceback.print_exc()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
asyncio.run(main())
|