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,908 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Communication Tools - Enable agents to call other agents or teams.
|
|
3
|
+
|
|
4
|
+
Provides hierarchical agent execution capabilities with security safeguards.
|
|
5
|
+
"""
|
|
6
|
+
import asyncio
|
|
7
|
+
import os
|
|
8
|
+
import time
|
|
9
|
+
import uuid
|
|
10
|
+
from typing import Any, Dict, List, Optional, Union, Literal
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
import httpx
|
|
13
|
+
import structlog
|
|
14
|
+
|
|
15
|
+
logger = structlog.get_logger()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AgentCommunicationTools:
|
|
19
|
+
"""
|
|
20
|
+
Tools for agent-to-agent and agent-to-team communication.
|
|
21
|
+
|
|
22
|
+
Enables hierarchical agent execution with:
|
|
23
|
+
- Parent-child execution tracking
|
|
24
|
+
- Execution depth control
|
|
25
|
+
- Circular call prevention
|
|
26
|
+
- Real-time status monitoring
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
allowed_operations: List[str] = None,
|
|
32
|
+
allowed_agents: Union[List[str], str] = None,
|
|
33
|
+
allowed_teams: Union[List[str], str] = None,
|
|
34
|
+
max_execution_depth: int = 2,
|
|
35
|
+
timeout: int = 300,
|
|
36
|
+
wait_for_completion: bool = True,
|
|
37
|
+
inherit_context: bool = True,
|
|
38
|
+
max_concurrent_calls: int = 3,
|
|
39
|
+
allow_session_continuation: bool = True,
|
|
40
|
+
streaming_enabled: bool = True,
|
|
41
|
+
parent_execution_id: Optional[str] = None,
|
|
42
|
+
execution_depth: int = 0,
|
|
43
|
+
control_plane_base_url: str = None,
|
|
44
|
+
kubiya_api_key: str = None,
|
|
45
|
+
organization_id: Optional[str] = None,
|
|
46
|
+
user_id: Optional[str] = None,
|
|
47
|
+
user_email: Optional[str] = None,
|
|
48
|
+
**kwargs
|
|
49
|
+
):
|
|
50
|
+
"""
|
|
51
|
+
Initialize Agent Communication Tools.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
allowed_operations: List of allowed tool operations
|
|
55
|
+
allowed_agents: List of agent IDs that can be called, or '*' for all
|
|
56
|
+
allowed_teams: List of team IDs that can be called, or '*' for all
|
|
57
|
+
max_execution_depth: Maximum nesting depth for child executions
|
|
58
|
+
timeout: Maximum wait time for child execution in seconds
|
|
59
|
+
wait_for_completion: Whether to wait for child execution to complete
|
|
60
|
+
inherit_context: Whether to pass parent execution context to child
|
|
61
|
+
max_concurrent_calls: Maximum number of concurrent child executions
|
|
62
|
+
allow_session_continuation: Allow following up on existing sessions
|
|
63
|
+
streaming_enabled: Stream child execution events to parent
|
|
64
|
+
parent_execution_id: ID of parent execution (for tracking)
|
|
65
|
+
execution_depth: Current depth in execution tree
|
|
66
|
+
control_plane_base_url: Control Plane API base URL
|
|
67
|
+
kubiya_api_key: Kubiya API key for authentication
|
|
68
|
+
organization_id: Organization ID for context
|
|
69
|
+
user_id: User ID for context
|
|
70
|
+
user_email: User email for context
|
|
71
|
+
**kwargs: Additional configuration
|
|
72
|
+
"""
|
|
73
|
+
self.allowed_operations = allowed_operations or ["get_execution_status"]
|
|
74
|
+
self.allowed_agents = allowed_agents or []
|
|
75
|
+
self.allowed_teams = allowed_teams or []
|
|
76
|
+
self.max_execution_depth = max_execution_depth
|
|
77
|
+
self.timeout = timeout
|
|
78
|
+
self.wait_for_completion = wait_for_completion
|
|
79
|
+
self.inherit_context = inherit_context
|
|
80
|
+
self.max_concurrent_calls = max_concurrent_calls
|
|
81
|
+
self.allow_session_continuation = allow_session_continuation
|
|
82
|
+
self.streaming_enabled = streaming_enabled
|
|
83
|
+
self.parent_execution_id = parent_execution_id
|
|
84
|
+
self.execution_depth = execution_depth
|
|
85
|
+
self.organization_id = organization_id
|
|
86
|
+
self.user_id = user_id
|
|
87
|
+
self.user_email = user_email
|
|
88
|
+
|
|
89
|
+
# Get control plane URL from environment or parameter
|
|
90
|
+
self.control_plane_base_url = (
|
|
91
|
+
control_plane_base_url or
|
|
92
|
+
os.environ.get("CONTROL_PLANE_BASE_URL") or
|
|
93
|
+
os.environ.get("CONTROL_PLANE_URL", "http://localhost:8000")
|
|
94
|
+
).rstrip("/")
|
|
95
|
+
|
|
96
|
+
self.kubiya_api_key = kubiya_api_key or os.environ.get("KUBIYA_API_KEY")
|
|
97
|
+
if not self.kubiya_api_key:
|
|
98
|
+
raise ValueError("KUBIYA_API_KEY is required for Agent Communication tools")
|
|
99
|
+
|
|
100
|
+
# Semaphore for concurrent execution limit
|
|
101
|
+
self._semaphore = asyncio.Semaphore(max_concurrent_calls)
|
|
102
|
+
|
|
103
|
+
# HTTP client for API calls
|
|
104
|
+
self._client = httpx.AsyncClient(timeout=httpx.Timeout(timeout, connect=5.0))
|
|
105
|
+
|
|
106
|
+
logger.info(
|
|
107
|
+
"agent_communication_tools_initialized",
|
|
108
|
+
allowed_operations=self.allowed_operations,
|
|
109
|
+
allowed_agents=self.allowed_agents if self.allowed_agents != "*" else "all",
|
|
110
|
+
allowed_teams=self.allowed_teams if self.allowed_teams != "*" else "all",
|
|
111
|
+
max_execution_depth=max_execution_depth,
|
|
112
|
+
execution_depth=execution_depth,
|
|
113
|
+
parent_execution_id=parent_execution_id,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def _get_headers(self) -> Dict[str, str]:
|
|
117
|
+
"""Get headers for API requests."""
|
|
118
|
+
return {
|
|
119
|
+
"Authorization": f"UserKey {self.kubiya_api_key}",
|
|
120
|
+
"Content-Type": "application/json",
|
|
121
|
+
"Accept": "application/json",
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
def _check_operation_allowed(self, operation: str) -> bool:
|
|
125
|
+
"""Check if an operation is allowed."""
|
|
126
|
+
return operation in self.allowed_operations
|
|
127
|
+
|
|
128
|
+
def _check_allowed_entity(self, entity_type: str, entity_id: str) -> bool:
|
|
129
|
+
"""
|
|
130
|
+
Check if entity is allowed to be called.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
entity_type: "agent" or "team"
|
|
134
|
+
entity_id: Agent or team ID
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
True if allowed, False otherwise
|
|
138
|
+
"""
|
|
139
|
+
allowed_list = self.allowed_agents if entity_type == "agent" else self.allowed_teams
|
|
140
|
+
|
|
141
|
+
# Wildcard = all allowed
|
|
142
|
+
if allowed_list == "*":
|
|
143
|
+
return True
|
|
144
|
+
|
|
145
|
+
# Check explicit whitelist
|
|
146
|
+
if isinstance(allowed_list, list):
|
|
147
|
+
return entity_id in allowed_list
|
|
148
|
+
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
def _check_execution_depth(self, child_depth: int) -> None:
|
|
152
|
+
"""
|
|
153
|
+
Check if execution depth is within limits.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
child_depth: Depth of child execution
|
|
157
|
+
|
|
158
|
+
Raises:
|
|
159
|
+
RuntimeError: If depth exceeds max_execution_depth
|
|
160
|
+
"""
|
|
161
|
+
if child_depth > self.max_execution_depth:
|
|
162
|
+
raise RuntimeError(
|
|
163
|
+
f"Execution depth limit exceeded: {child_depth} > {self.max_execution_depth}. "
|
|
164
|
+
f"Cannot create deeper child executions."
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
async def _get_execution_chain(self, execution_id: str) -> List[Dict[str, Any]]:
|
|
168
|
+
"""
|
|
169
|
+
Build execution chain from root to current execution.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
execution_id: Execution ID to start from
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List of execution info dicts with execution_id, entity_type, entity_id
|
|
176
|
+
"""
|
|
177
|
+
chain = []
|
|
178
|
+
current_id = execution_id
|
|
179
|
+
max_depth = 20 # Prevent infinite loops
|
|
180
|
+
|
|
181
|
+
while current_id and len(chain) < max_depth:
|
|
182
|
+
try:
|
|
183
|
+
url = f"{self.control_plane_base_url}/api/v1/executions/{current_id}"
|
|
184
|
+
response = await self._client.get(url, headers=self._get_headers())
|
|
185
|
+
|
|
186
|
+
if response.status_code != 200:
|
|
187
|
+
logger.warning(
|
|
188
|
+
"failed_to_fetch_execution_in_chain",
|
|
189
|
+
execution_id=current_id,
|
|
190
|
+
status_code=response.status_code
|
|
191
|
+
)
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
execution = response.json()
|
|
195
|
+
chain.append({
|
|
196
|
+
"execution_id": current_id,
|
|
197
|
+
"entity_type": execution.get("entity_type"),
|
|
198
|
+
"entity_id": execution.get("entity_id"),
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
# Get parent execution ID
|
|
202
|
+
current_id = execution.get("parent_execution_id")
|
|
203
|
+
|
|
204
|
+
except Exception as e:
|
|
205
|
+
logger.error(
|
|
206
|
+
"error_building_execution_chain",
|
|
207
|
+
execution_id=current_id,
|
|
208
|
+
error=str(e)
|
|
209
|
+
)
|
|
210
|
+
break
|
|
211
|
+
|
|
212
|
+
return chain
|
|
213
|
+
|
|
214
|
+
def _is_circular_call(self, chain: List[Dict[str, Any]], target_entity_id: str) -> bool:
|
|
215
|
+
"""
|
|
216
|
+
Check if target_entity_id appears in execution chain (circular call).
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
chain: Execution chain from _get_execution_chain
|
|
220
|
+
target_entity_id: Agent or team ID to check
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
True if circular call detected, False otherwise
|
|
224
|
+
"""
|
|
225
|
+
return any(e.get("entity_id") == target_entity_id for e in chain)
|
|
226
|
+
|
|
227
|
+
async def _check_circular_execution(self, target_entity_id: str) -> None:
|
|
228
|
+
"""
|
|
229
|
+
Check if calling target_entity_id would create a circular execution.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
target_entity_id: Agent or team ID to check
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
RuntimeError: If circular call detected
|
|
236
|
+
"""
|
|
237
|
+
if not self.parent_execution_id:
|
|
238
|
+
# No parent, so no cycle possible
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
# Build execution chain
|
|
242
|
+
chain = await self._get_execution_chain(self.parent_execution_id)
|
|
243
|
+
|
|
244
|
+
# Check for circular call
|
|
245
|
+
if self._is_circular_call(chain, target_entity_id):
|
|
246
|
+
chain_str = " -> ".join([e["entity_id"] for e in chain])
|
|
247
|
+
raise RuntimeError(
|
|
248
|
+
f"Circular execution detected: {target_entity_id} already appears in execution chain. "
|
|
249
|
+
f"Chain: {chain_str} -> {target_entity_id}"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def _build_child_context(self) -> Dict[str, Any]:
|
|
253
|
+
"""
|
|
254
|
+
Build context to pass to child execution.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Dict with parent context information
|
|
258
|
+
"""
|
|
259
|
+
context = {
|
|
260
|
+
"parent_execution_id": self.parent_execution_id,
|
|
261
|
+
"execution_depth": self.execution_depth + 1,
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if self.inherit_context:
|
|
265
|
+
# Add user context
|
|
266
|
+
if self.user_id:
|
|
267
|
+
context["user_id"] = self.user_id
|
|
268
|
+
if self.user_email:
|
|
269
|
+
context["user_email"] = self.user_email
|
|
270
|
+
if self.organization_id:
|
|
271
|
+
context["organization_id"] = self.organization_id
|
|
272
|
+
|
|
273
|
+
return context
|
|
274
|
+
|
|
275
|
+
async def _wait_for_execution(
|
|
276
|
+
self,
|
|
277
|
+
execution_id: str,
|
|
278
|
+
timeout: Optional[int] = None
|
|
279
|
+
) -> Dict[str, Any]:
|
|
280
|
+
"""
|
|
281
|
+
Poll execution status until complete or timeout.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
execution_id: Execution ID to wait for
|
|
285
|
+
timeout: Timeout in seconds (defaults to self.timeout)
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
Dict with execution result
|
|
289
|
+
"""
|
|
290
|
+
timeout = timeout or self.timeout
|
|
291
|
+
start_time = time.time()
|
|
292
|
+
poll_interval = 2 # seconds
|
|
293
|
+
|
|
294
|
+
while True:
|
|
295
|
+
elapsed = time.time() - start_time
|
|
296
|
+
|
|
297
|
+
if elapsed >= timeout:
|
|
298
|
+
logger.warning(
|
|
299
|
+
"execution_timeout",
|
|
300
|
+
execution_id=execution_id,
|
|
301
|
+
timeout=timeout
|
|
302
|
+
)
|
|
303
|
+
return {
|
|
304
|
+
"execution_id": execution_id,
|
|
305
|
+
"status": "timeout",
|
|
306
|
+
"error": f"Execution exceeded timeout of {timeout}s",
|
|
307
|
+
"duration_ms": int(elapsed * 1000),
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Fetch execution status
|
|
311
|
+
try:
|
|
312
|
+
status_result = await self.get_execution_status(
|
|
313
|
+
execution_id=execution_id,
|
|
314
|
+
include_events=False,
|
|
315
|
+
include_session=False
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
status = status_result.get("status")
|
|
319
|
+
|
|
320
|
+
# Check if completed
|
|
321
|
+
if status in ["completed", "failed", "cancelled"]:
|
|
322
|
+
return status_result
|
|
323
|
+
|
|
324
|
+
# Still running or waiting for input, continue polling
|
|
325
|
+
await asyncio.sleep(poll_interval)
|
|
326
|
+
|
|
327
|
+
except Exception as e:
|
|
328
|
+
logger.error(
|
|
329
|
+
"error_polling_execution_status",
|
|
330
|
+
execution_id=execution_id,
|
|
331
|
+
error=str(e)
|
|
332
|
+
)
|
|
333
|
+
return {
|
|
334
|
+
"execution_id": execution_id,
|
|
335
|
+
"status": "error",
|
|
336
|
+
"error": f"Failed to poll execution status: {str(e)}",
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async def _stream_child_events(
|
|
340
|
+
self,
|
|
341
|
+
child_execution_id: str,
|
|
342
|
+
parent_execution_id: str
|
|
343
|
+
) -> None:
|
|
344
|
+
"""
|
|
345
|
+
Stream child execution events to parent execution (background task).
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
child_execution_id: Child execution ID
|
|
349
|
+
parent_execution_id: Parent execution ID to stream events to
|
|
350
|
+
"""
|
|
351
|
+
# TODO: Implement event streaming from child to parent
|
|
352
|
+
# This would require subscribing to child execution events via WebSocket or SSE
|
|
353
|
+
# and republishing them to the parent execution
|
|
354
|
+
logger.info(
|
|
355
|
+
"event_streaming_placeholder",
|
|
356
|
+
child_execution_id=child_execution_id,
|
|
357
|
+
parent_execution_id=parent_execution_id,
|
|
358
|
+
message="Event streaming not yet implemented"
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
async def execute_agent(
|
|
362
|
+
self,
|
|
363
|
+
agent_id: str,
|
|
364
|
+
prompt: str,
|
|
365
|
+
wait_for_completion: Optional[bool] = None,
|
|
366
|
+
timeout: Optional[int] = None,
|
|
367
|
+
inherit_context: Optional[bool] = None,
|
|
368
|
+
) -> Dict[str, Any]:
|
|
369
|
+
"""
|
|
370
|
+
Execute another agent with a specific prompt.
|
|
371
|
+
|
|
372
|
+
Creates a new child execution and optionally waits for completion.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
agent_id: The ID of the agent to execute
|
|
376
|
+
prompt: The prompt/instruction to send to the agent
|
|
377
|
+
wait_for_completion: Whether to wait for the agent to finish (defaults to config)
|
|
378
|
+
timeout: Maximum wait time in seconds (defaults to config)
|
|
379
|
+
inherit_context: Whether to pass parent execution context (defaults to config)
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
Dict containing:
|
|
383
|
+
- execution_id: ID of the child execution
|
|
384
|
+
- status: Current execution status
|
|
385
|
+
- result: Final result if wait_for_completion=True
|
|
386
|
+
- events: List of execution events
|
|
387
|
+
|
|
388
|
+
Raises:
|
|
389
|
+
ValueError: If agent_id not in allowed_agents or operation not allowed
|
|
390
|
+
RuntimeError: If max_execution_depth exceeded or circular execution detected
|
|
391
|
+
"""
|
|
392
|
+
# Check operation allowed
|
|
393
|
+
if not self._check_operation_allowed("execute_agent"):
|
|
394
|
+
raise ValueError(
|
|
395
|
+
"Operation 'execute_agent' not allowed. "
|
|
396
|
+
f"Allowed operations: {self.allowed_operations}"
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
# Check agent allowed
|
|
400
|
+
if not self._check_allowed_entity("agent", agent_id):
|
|
401
|
+
raise ValueError(
|
|
402
|
+
f"Agent '{agent_id}' not in allowed agents list. "
|
|
403
|
+
f"Allowed agents: {self.allowed_agents}"
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
# Use defaults if not specified
|
|
407
|
+
wait = wait_for_completion if wait_for_completion is not None else self.wait_for_completion
|
|
408
|
+
timeout_val = timeout if timeout is not None else self.timeout
|
|
409
|
+
inherit = inherit_context if inherit_context is not None else self.inherit_context
|
|
410
|
+
|
|
411
|
+
# Check execution depth
|
|
412
|
+
child_depth = self.execution_depth + 1
|
|
413
|
+
self._check_execution_depth(child_depth)
|
|
414
|
+
|
|
415
|
+
# Check circular execution
|
|
416
|
+
await self._check_circular_execution(agent_id)
|
|
417
|
+
|
|
418
|
+
# Acquire semaphore for concurrent execution limit
|
|
419
|
+
async with self._semaphore:
|
|
420
|
+
# Create child execution
|
|
421
|
+
execution_id = str(uuid.uuid4())
|
|
422
|
+
|
|
423
|
+
logger.info(
|
|
424
|
+
"creating_child_agent_execution",
|
|
425
|
+
parent_execution_id=self.parent_execution_id,
|
|
426
|
+
child_execution_id=execution_id,
|
|
427
|
+
agent_id=agent_id,
|
|
428
|
+
execution_depth=child_depth,
|
|
429
|
+
wait_for_completion=wait
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
try:
|
|
433
|
+
# Build child context
|
|
434
|
+
child_context = self._build_child_context() if inherit else {}
|
|
435
|
+
|
|
436
|
+
# Create execution via Control Plane API
|
|
437
|
+
url = f"{self.control_plane_base_url}/api/v1/executions"
|
|
438
|
+
payload = {
|
|
439
|
+
"execution_id": execution_id,
|
|
440
|
+
"entity_type": "agent",
|
|
441
|
+
"entity_id": agent_id,
|
|
442
|
+
"prompt": prompt,
|
|
443
|
+
"parent_execution_id": self.parent_execution_id,
|
|
444
|
+
"execution_depth": child_depth,
|
|
445
|
+
"context": child_context,
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if self.organization_id:
|
|
449
|
+
payload["organization_id"] = self.organization_id
|
|
450
|
+
|
|
451
|
+
response = await self._client.post(
|
|
452
|
+
url,
|
|
453
|
+
headers=self._get_headers(),
|
|
454
|
+
json=payload
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
if response.status_code not in [200, 201, 202]:
|
|
458
|
+
error_msg = f"Failed to create execution: {response.status_code} {response.text}"
|
|
459
|
+
logger.error(
|
|
460
|
+
"create_execution_failed",
|
|
461
|
+
execution_id=execution_id,
|
|
462
|
+
agent_id=agent_id,
|
|
463
|
+
status_code=response.status_code,
|
|
464
|
+
error=response.text[:500]
|
|
465
|
+
)
|
|
466
|
+
return {
|
|
467
|
+
"execution_id": execution_id,
|
|
468
|
+
"status": "failed",
|
|
469
|
+
"error": error_msg,
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
# Start event streaming if enabled (background task)
|
|
473
|
+
if self.streaming_enabled and self.parent_execution_id:
|
|
474
|
+
asyncio.create_task(
|
|
475
|
+
self._stream_child_events(execution_id, self.parent_execution_id)
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
# Wait for completion if requested
|
|
479
|
+
if wait:
|
|
480
|
+
result = await self._wait_for_execution(execution_id, timeout_val)
|
|
481
|
+
logger.info(
|
|
482
|
+
"child_agent_execution_completed",
|
|
483
|
+
execution_id=execution_id,
|
|
484
|
+
agent_id=agent_id,
|
|
485
|
+
status=result.get("status")
|
|
486
|
+
)
|
|
487
|
+
return result
|
|
488
|
+
else:
|
|
489
|
+
# Return immediately with execution ID
|
|
490
|
+
return {
|
|
491
|
+
"execution_id": execution_id,
|
|
492
|
+
"status": "running",
|
|
493
|
+
"entity_type": "agent",
|
|
494
|
+
"entity_id": agent_id,
|
|
495
|
+
"parent_execution_id": self.parent_execution_id,
|
|
496
|
+
"execution_depth": child_depth,
|
|
497
|
+
"message": "Execution started asynchronously. Use get_execution_status() to check progress.",
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
except Exception as e:
|
|
501
|
+
logger.error(
|
|
502
|
+
"execute_agent_error",
|
|
503
|
+
execution_id=execution_id,
|
|
504
|
+
agent_id=agent_id,
|
|
505
|
+
error=str(e)
|
|
506
|
+
)
|
|
507
|
+
return {
|
|
508
|
+
"execution_id": execution_id,
|
|
509
|
+
"status": "failed",
|
|
510
|
+
"error": f"Failed to execute agent: {str(e)}",
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
async def execute_team(
|
|
514
|
+
self,
|
|
515
|
+
team_id: str,
|
|
516
|
+
prompt: str,
|
|
517
|
+
wait_for_completion: Optional[bool] = None,
|
|
518
|
+
timeout: Optional[int] = None,
|
|
519
|
+
inherit_context: Optional[bool] = None,
|
|
520
|
+
) -> Dict[str, Any]:
|
|
521
|
+
"""
|
|
522
|
+
Execute a team with a specific prompt.
|
|
523
|
+
|
|
524
|
+
Creates a new child team execution with multi-agent collaboration.
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
team_id: The ID of the team to execute
|
|
528
|
+
prompt: The prompt/instruction to send to the team
|
|
529
|
+
wait_for_completion: Whether to wait for team to finish
|
|
530
|
+
timeout: Maximum wait time in seconds
|
|
531
|
+
inherit_context: Whether to pass parent execution context
|
|
532
|
+
|
|
533
|
+
Returns:
|
|
534
|
+
Dict containing:
|
|
535
|
+
- execution_id: ID of the child execution
|
|
536
|
+
- status: Current execution status
|
|
537
|
+
- result: Final result if wait_for_completion=True
|
|
538
|
+
- team_members: List of agents in the team
|
|
539
|
+
- events: List of execution events
|
|
540
|
+
|
|
541
|
+
Raises:
|
|
542
|
+
ValueError: If team_id not in allowed_teams or operation not allowed
|
|
543
|
+
RuntimeError: If max_execution_depth exceeded or circular execution detected
|
|
544
|
+
"""
|
|
545
|
+
# Check operation allowed
|
|
546
|
+
if not self._check_operation_allowed("execute_team"):
|
|
547
|
+
raise ValueError(
|
|
548
|
+
"Operation 'execute_team' not allowed. "
|
|
549
|
+
f"Allowed operations: {self.allowed_operations}"
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
# Check team allowed
|
|
553
|
+
if not self._check_allowed_entity("team", team_id):
|
|
554
|
+
raise ValueError(
|
|
555
|
+
f"Team '{team_id}' not in allowed teams list. "
|
|
556
|
+
f"Allowed teams: {self.allowed_teams}"
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
# Use defaults if not specified
|
|
560
|
+
wait = wait_for_completion if wait_for_completion is not None else self.wait_for_completion
|
|
561
|
+
timeout_val = timeout if timeout is not None else self.timeout
|
|
562
|
+
inherit = inherit_context if inherit_context is not None else self.inherit_context
|
|
563
|
+
|
|
564
|
+
# Check execution depth
|
|
565
|
+
child_depth = self.execution_depth + 1
|
|
566
|
+
self._check_execution_depth(child_depth)
|
|
567
|
+
|
|
568
|
+
# Check circular execution
|
|
569
|
+
await self._check_circular_execution(team_id)
|
|
570
|
+
|
|
571
|
+
# Acquire semaphore for concurrent execution limit
|
|
572
|
+
async with self._semaphore:
|
|
573
|
+
# Create child execution
|
|
574
|
+
execution_id = str(uuid.uuid4())
|
|
575
|
+
|
|
576
|
+
logger.info(
|
|
577
|
+
"creating_child_team_execution",
|
|
578
|
+
parent_execution_id=self.parent_execution_id,
|
|
579
|
+
child_execution_id=execution_id,
|
|
580
|
+
team_id=team_id,
|
|
581
|
+
execution_depth=child_depth,
|
|
582
|
+
wait_for_completion=wait
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
try:
|
|
586
|
+
# Build child context
|
|
587
|
+
child_context = self._build_child_context() if inherit else {}
|
|
588
|
+
|
|
589
|
+
# Create execution via Control Plane API
|
|
590
|
+
url = f"{self.control_plane_base_url}/api/v1/executions"
|
|
591
|
+
payload = {
|
|
592
|
+
"execution_id": execution_id,
|
|
593
|
+
"entity_type": "team",
|
|
594
|
+
"entity_id": team_id,
|
|
595
|
+
"prompt": prompt,
|
|
596
|
+
"parent_execution_id": self.parent_execution_id,
|
|
597
|
+
"execution_depth": child_depth,
|
|
598
|
+
"context": child_context,
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if self.organization_id:
|
|
602
|
+
payload["organization_id"] = self.organization_id
|
|
603
|
+
|
|
604
|
+
response = await self._client.post(
|
|
605
|
+
url,
|
|
606
|
+
headers=self._get_headers(),
|
|
607
|
+
json=payload
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
if response.status_code not in [200, 201, 202]:
|
|
611
|
+
error_msg = f"Failed to create execution: {response.status_code} {response.text}"
|
|
612
|
+
logger.error(
|
|
613
|
+
"create_execution_failed",
|
|
614
|
+
execution_id=execution_id,
|
|
615
|
+
team_id=team_id,
|
|
616
|
+
status_code=response.status_code,
|
|
617
|
+
error=response.text[:500]
|
|
618
|
+
)
|
|
619
|
+
return {
|
|
620
|
+
"execution_id": execution_id,
|
|
621
|
+
"status": "failed",
|
|
622
|
+
"error": error_msg,
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
# Start event streaming if enabled (background task)
|
|
626
|
+
if self.streaming_enabled and self.parent_execution_id:
|
|
627
|
+
asyncio.create_task(
|
|
628
|
+
self._stream_child_events(execution_id, self.parent_execution_id)
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
# Wait for completion if requested
|
|
632
|
+
if wait:
|
|
633
|
+
result = await self._wait_for_execution(execution_id, timeout_val)
|
|
634
|
+
logger.info(
|
|
635
|
+
"child_team_execution_completed",
|
|
636
|
+
execution_id=execution_id,
|
|
637
|
+
team_id=team_id,
|
|
638
|
+
status=result.get("status")
|
|
639
|
+
)
|
|
640
|
+
return result
|
|
641
|
+
else:
|
|
642
|
+
# Return immediately with execution ID
|
|
643
|
+
return {
|
|
644
|
+
"execution_id": execution_id,
|
|
645
|
+
"status": "running",
|
|
646
|
+
"entity_type": "team",
|
|
647
|
+
"entity_id": team_id,
|
|
648
|
+
"parent_execution_id": self.parent_execution_id,
|
|
649
|
+
"execution_depth": child_depth,
|
|
650
|
+
"message": "Execution started asynchronously. Use get_execution_status() to check progress.",
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
except Exception as e:
|
|
654
|
+
logger.error(
|
|
655
|
+
"execute_team_error",
|
|
656
|
+
execution_id=execution_id,
|
|
657
|
+
team_id=team_id,
|
|
658
|
+
error=str(e)
|
|
659
|
+
)
|
|
660
|
+
return {
|
|
661
|
+
"execution_id": execution_id,
|
|
662
|
+
"status": "failed",
|
|
663
|
+
"error": f"Failed to execute team: {str(e)}",
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
async def followup_execution(
|
|
667
|
+
self,
|
|
668
|
+
execution_id: str,
|
|
669
|
+
followup_prompt: str,
|
|
670
|
+
wait_for_completion: Optional[bool] = None,
|
|
671
|
+
timeout: Optional[int] = None,
|
|
672
|
+
) -> Dict[str, Any]:
|
|
673
|
+
"""
|
|
674
|
+
Send a followup prompt to an existing execution (continue conversation).
|
|
675
|
+
|
|
676
|
+
Only available if allow_session_continuation=True.
|
|
677
|
+
|
|
678
|
+
Args:
|
|
679
|
+
execution_id: The ID of the execution to follow up on
|
|
680
|
+
followup_prompt: Additional prompt/instruction to add to conversation
|
|
681
|
+
wait_for_completion: Whether to wait for response
|
|
682
|
+
timeout: Maximum wait time in seconds
|
|
683
|
+
|
|
684
|
+
Returns:
|
|
685
|
+
Dict containing:
|
|
686
|
+
- execution_id: Same execution ID
|
|
687
|
+
- status: Current execution status
|
|
688
|
+
- result: Response to followup
|
|
689
|
+
- message_count: Total messages in session
|
|
690
|
+
|
|
691
|
+
Raises:
|
|
692
|
+
RuntimeError: If allow_session_continuation=False
|
|
693
|
+
ValueError: If execution_id not found or not accessible or operation not allowed
|
|
694
|
+
"""
|
|
695
|
+
# Check operation allowed
|
|
696
|
+
if not self._check_operation_allowed("followup_execution"):
|
|
697
|
+
raise ValueError(
|
|
698
|
+
"Operation 'followup_execution' not allowed. "
|
|
699
|
+
f"Allowed operations: {self.allowed_operations}"
|
|
700
|
+
)
|
|
701
|
+
|
|
702
|
+
# Check if session continuation is allowed
|
|
703
|
+
if not self.allow_session_continuation:
|
|
704
|
+
raise RuntimeError(
|
|
705
|
+
"Session continuation is not allowed. "
|
|
706
|
+
"Set allow_session_continuation=True to enable this operation."
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
# Use defaults if not specified
|
|
710
|
+
wait = wait_for_completion if wait_for_completion is not None else self.wait_for_completion
|
|
711
|
+
timeout_val = timeout if timeout is not None else self.timeout
|
|
712
|
+
|
|
713
|
+
logger.info(
|
|
714
|
+
"following_up_execution",
|
|
715
|
+
execution_id=execution_id,
|
|
716
|
+
wait_for_completion=wait
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
try:
|
|
720
|
+
# Send followup via Control Plane API
|
|
721
|
+
url = f"{self.control_plane_base_url}/api/v1/executions/{execution_id}/followup"
|
|
722
|
+
payload = {
|
|
723
|
+
"prompt": followup_prompt,
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
response = await self._client.post(
|
|
727
|
+
url,
|
|
728
|
+
headers=self._get_headers(),
|
|
729
|
+
json=payload
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
if response.status_code not in [200, 201, 202]:
|
|
733
|
+
error_msg = f"Failed to send followup: {response.status_code} {response.text}"
|
|
734
|
+
logger.error(
|
|
735
|
+
"followup_execution_failed",
|
|
736
|
+
execution_id=execution_id,
|
|
737
|
+
status_code=response.status_code,
|
|
738
|
+
error=response.text[:500]
|
|
739
|
+
)
|
|
740
|
+
return {
|
|
741
|
+
"execution_id": execution_id,
|
|
742
|
+
"status": "failed",
|
|
743
|
+
"error": error_msg,
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
# Wait for completion if requested
|
|
747
|
+
if wait:
|
|
748
|
+
result = await self._wait_for_execution(execution_id, timeout_val)
|
|
749
|
+
logger.info(
|
|
750
|
+
"followup_execution_completed",
|
|
751
|
+
execution_id=execution_id,
|
|
752
|
+
status=result.get("status")
|
|
753
|
+
)
|
|
754
|
+
return result
|
|
755
|
+
else:
|
|
756
|
+
return {
|
|
757
|
+
"execution_id": execution_id,
|
|
758
|
+
"status": "running",
|
|
759
|
+
"message": "Followup sent successfully. Use get_execution_status() to check progress.",
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
except Exception as e:
|
|
763
|
+
logger.error(
|
|
764
|
+
"followup_execution_error",
|
|
765
|
+
execution_id=execution_id,
|
|
766
|
+
error=str(e)
|
|
767
|
+
)
|
|
768
|
+
return {
|
|
769
|
+
"execution_id": execution_id,
|
|
770
|
+
"status": "failed",
|
|
771
|
+
"error": f"Failed to send followup: {str(e)}",
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async def get_execution_status(
|
|
775
|
+
self,
|
|
776
|
+
execution_id: str,
|
|
777
|
+
include_events: bool = False,
|
|
778
|
+
include_session: bool = False,
|
|
779
|
+
) -> Dict[str, Any]:
|
|
780
|
+
"""
|
|
781
|
+
Get the current status of an execution.
|
|
782
|
+
|
|
783
|
+
Available for all variants (monitoring-only to full orchestration).
|
|
784
|
+
|
|
785
|
+
Args:
|
|
786
|
+
execution_id: The ID of the execution to check
|
|
787
|
+
include_events: Whether to include full event history
|
|
788
|
+
include_session: Whether to include conversation history
|
|
789
|
+
|
|
790
|
+
Returns:
|
|
791
|
+
Dict containing:
|
|
792
|
+
- execution_id: Execution ID
|
|
793
|
+
- status: Current status (pending, running, completed, failed)
|
|
794
|
+
- entity_type: "agent" or "team"
|
|
795
|
+
- entity_id: Agent or team ID
|
|
796
|
+
- created_at: Start timestamp
|
|
797
|
+
- completed_at: End timestamp (if completed)
|
|
798
|
+
- duration_ms: Execution duration
|
|
799
|
+
- result: Final result (if completed)
|
|
800
|
+
- error: Error message (if failed)
|
|
801
|
+
- events: Event history (if include_events=True)
|
|
802
|
+
- session: Conversation history (if include_session=True)
|
|
803
|
+
|
|
804
|
+
Raises:
|
|
805
|
+
ValueError: If operation not allowed
|
|
806
|
+
"""
|
|
807
|
+
# Check operation allowed
|
|
808
|
+
if not self._check_operation_allowed("get_execution_status"):
|
|
809
|
+
raise ValueError(
|
|
810
|
+
"Operation 'get_execution_status' not allowed. "
|
|
811
|
+
f"Allowed operations: {self.allowed_operations}"
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
logger.debug(
|
|
815
|
+
"fetching_execution_status",
|
|
816
|
+
execution_id=execution_id,
|
|
817
|
+
include_events=include_events,
|
|
818
|
+
include_session=include_session
|
|
819
|
+
)
|
|
820
|
+
|
|
821
|
+
try:
|
|
822
|
+
# Fetch execution from Control Plane API
|
|
823
|
+
url = f"{self.control_plane_base_url}/api/v1/executions/{execution_id}"
|
|
824
|
+
params = {}
|
|
825
|
+
if include_events:
|
|
826
|
+
params["include_events"] = "true"
|
|
827
|
+
if include_session:
|
|
828
|
+
params["include_session"] = "true"
|
|
829
|
+
|
|
830
|
+
response = await self._client.get(
|
|
831
|
+
url,
|
|
832
|
+
headers=self._get_headers(),
|
|
833
|
+
params=params
|
|
834
|
+
)
|
|
835
|
+
|
|
836
|
+
if response.status_code == 404:
|
|
837
|
+
return {
|
|
838
|
+
"execution_id": execution_id,
|
|
839
|
+
"status": "not_found",
|
|
840
|
+
"error": f"Execution '{execution_id}' not found",
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if response.status_code != 200:
|
|
844
|
+
error_msg = f"Failed to fetch execution: {response.status_code} {response.text}"
|
|
845
|
+
logger.error(
|
|
846
|
+
"fetch_execution_failed",
|
|
847
|
+
execution_id=execution_id,
|
|
848
|
+
status_code=response.status_code,
|
|
849
|
+
error=response.text[:500]
|
|
850
|
+
)
|
|
851
|
+
return {
|
|
852
|
+
"execution_id": execution_id,
|
|
853
|
+
"status": "error",
|
|
854
|
+
"error": error_msg,
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
execution_data = response.json()
|
|
858
|
+
|
|
859
|
+
# Format response
|
|
860
|
+
result = {
|
|
861
|
+
"execution_id": execution_id,
|
|
862
|
+
"status": execution_data.get("status", "unknown"),
|
|
863
|
+
"entity_type": execution_data.get("entity_type"),
|
|
864
|
+
"entity_id": execution_data.get("entity_id"),
|
|
865
|
+
"created_at": execution_data.get("created_at"),
|
|
866
|
+
"completed_at": execution_data.get("completed_at"),
|
|
867
|
+
"duration_ms": execution_data.get("duration_ms"),
|
|
868
|
+
"parent_execution_id": execution_data.get("parent_execution_id"),
|
|
869
|
+
"execution_depth": execution_data.get("execution_depth", 0),
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
# Add result if completed
|
|
873
|
+
if execution_data.get("result"):
|
|
874
|
+
result["result"] = execution_data["result"]
|
|
875
|
+
|
|
876
|
+
# Add error if failed
|
|
877
|
+
if execution_data.get("error"):
|
|
878
|
+
result["error"] = execution_data["error"]
|
|
879
|
+
|
|
880
|
+
# Add events if requested
|
|
881
|
+
if include_events and execution_data.get("events"):
|
|
882
|
+
result["events"] = execution_data["events"]
|
|
883
|
+
|
|
884
|
+
# Add session if requested
|
|
885
|
+
if include_session and execution_data.get("session"):
|
|
886
|
+
result["session"] = execution_data["session"]
|
|
887
|
+
|
|
888
|
+
return result
|
|
889
|
+
|
|
890
|
+
except Exception as e:
|
|
891
|
+
logger.error(
|
|
892
|
+
"get_execution_status_error",
|
|
893
|
+
execution_id=execution_id,
|
|
894
|
+
error=str(e)
|
|
895
|
+
)
|
|
896
|
+
return {
|
|
897
|
+
"execution_id": execution_id,
|
|
898
|
+
"status": "error",
|
|
899
|
+
"error": f"Failed to get execution status: {str(e)}",
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
async def __aenter__(self):
|
|
903
|
+
"""Async context manager entry."""
|
|
904
|
+
return self
|
|
905
|
+
|
|
906
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
907
|
+
"""Async context manager exit - cleanup."""
|
|
908
|
+
await self._client.aclose()
|