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,520 @@
|
|
|
1
|
+
"""Agent execution workflow for Temporal"""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import timedelta
|
|
5
|
+
from typing import Optional, List, Dict, Any
|
|
6
|
+
from temporalio import workflow
|
|
7
|
+
import asyncio
|
|
8
|
+
|
|
9
|
+
with workflow.unsafe.imports_passed_through():
|
|
10
|
+
from control_plane_api.app.activities.agent_activities import (
|
|
11
|
+
execute_agent_llm,
|
|
12
|
+
update_execution_status,
|
|
13
|
+
update_agent_status,
|
|
14
|
+
ActivityExecuteAgentInput,
|
|
15
|
+
ActivityUpdateExecutionInput,
|
|
16
|
+
ActivityUpdateAgentInput,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class AgentExecutionInput:
|
|
22
|
+
"""Input for agent execution workflow"""
|
|
23
|
+
execution_id: str
|
|
24
|
+
agent_id: str
|
|
25
|
+
organization_id: str
|
|
26
|
+
prompt: str
|
|
27
|
+
system_prompt: Optional[str] = None
|
|
28
|
+
model_id: Optional[str] = None
|
|
29
|
+
model_config: dict = None
|
|
30
|
+
agent_config: dict = None
|
|
31
|
+
mcp_servers: dict = None # MCP servers configuration
|
|
32
|
+
user_metadata: dict = None
|
|
33
|
+
runtime_type: str = "default" # "default" (Agno) or "claude_code"
|
|
34
|
+
control_plane_url: Optional[str] = None # Control Plane URL for fetching credentials/secrets
|
|
35
|
+
api_key: Optional[str] = None # API key for authentication
|
|
36
|
+
initial_message_timestamp: Optional[str] = None # Real-time timestamp for initial message
|
|
37
|
+
graph_api_url: Optional[str] = None # Context graph API URL for memory tools
|
|
38
|
+
dataset_name: Optional[str] = None # Dataset name for memory scoping (environment name)
|
|
39
|
+
|
|
40
|
+
def __post_init__(self):
|
|
41
|
+
if self.model_config is None:
|
|
42
|
+
self.model_config = {}
|
|
43
|
+
if self.agent_config is None:
|
|
44
|
+
self.agent_config = {}
|
|
45
|
+
if self.mcp_servers is None:
|
|
46
|
+
self.mcp_servers = {}
|
|
47
|
+
if self.user_metadata is None:
|
|
48
|
+
self.user_metadata = {}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class TeamExecutionInput:
|
|
53
|
+
"""Input for team execution workflow (uses same workflow as agent)"""
|
|
54
|
+
execution_id: str
|
|
55
|
+
team_id: str
|
|
56
|
+
organization_id: str
|
|
57
|
+
prompt: str
|
|
58
|
+
system_prompt: Optional[str] = None
|
|
59
|
+
model_id: Optional[str] = None
|
|
60
|
+
model_config: dict = None
|
|
61
|
+
team_config: dict = None
|
|
62
|
+
mcp_servers: dict = None # MCP servers configuration
|
|
63
|
+
user_metadata: dict = None
|
|
64
|
+
runtime_type: str = "default" # "default" (Agno) or "claude_code"
|
|
65
|
+
control_plane_url: Optional[str] = None # Control Plane URL for fetching credentials/secrets
|
|
66
|
+
api_key: Optional[str] = None # API key for authentication
|
|
67
|
+
initial_message_timestamp: Optional[str] = None # Real-time timestamp for initial message
|
|
68
|
+
graph_api_url: Optional[str] = None # Context graph API URL for memory tools
|
|
69
|
+
dataset_name: Optional[str] = None # Dataset name for memory scoping (environment name)
|
|
70
|
+
|
|
71
|
+
def __post_init__(self):
|
|
72
|
+
if self.model_config is None:
|
|
73
|
+
self.model_config = {}
|
|
74
|
+
if self.team_config is None:
|
|
75
|
+
self.team_config = {}
|
|
76
|
+
if self.mcp_servers is None:
|
|
77
|
+
self.mcp_servers = {}
|
|
78
|
+
if self.user_metadata is None:
|
|
79
|
+
self.user_metadata = {}
|
|
80
|
+
|
|
81
|
+
def to_agent_input(self) -> AgentExecutionInput:
|
|
82
|
+
"""Convert TeamExecutionInput to AgentExecutionInput for workflow reuse"""
|
|
83
|
+
return AgentExecutionInput(
|
|
84
|
+
execution_id=self.execution_id,
|
|
85
|
+
agent_id=self.team_id, # Use team_id as agent_id
|
|
86
|
+
organization_id=self.organization_id,
|
|
87
|
+
prompt=self.prompt,
|
|
88
|
+
system_prompt=self.system_prompt,
|
|
89
|
+
model_id=self.model_id,
|
|
90
|
+
model_config=self.model_config,
|
|
91
|
+
agent_config=self.team_config,
|
|
92
|
+
mcp_servers=self.mcp_servers,
|
|
93
|
+
user_metadata=self.user_metadata,
|
|
94
|
+
runtime_type=self.runtime_type,
|
|
95
|
+
control_plane_url=self.control_plane_url,
|
|
96
|
+
api_key=self.api_key,
|
|
97
|
+
initial_message_timestamp=self.initial_message_timestamp,
|
|
98
|
+
graph_api_url=self.graph_api_url,
|
|
99
|
+
dataset_name=self.dataset_name,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class ChatMessage:
|
|
105
|
+
"""Represents a message in the conversation"""
|
|
106
|
+
role: str # "user", "assistant", "system", "tool"
|
|
107
|
+
content: str
|
|
108
|
+
timestamp: str
|
|
109
|
+
tool_name: Optional[str] = None
|
|
110
|
+
tool_input: Optional[Dict[str, Any]] = None
|
|
111
|
+
tool_output: Optional[Dict[str, Any]] = None
|
|
112
|
+
message_id: Optional[str] = None # Unique identifier for deduplication
|
|
113
|
+
# User attribution for messages
|
|
114
|
+
user_id: Optional[str] = None
|
|
115
|
+
user_name: Optional[str] = None
|
|
116
|
+
user_email: Optional[str] = None
|
|
117
|
+
user_avatar: Optional[str] = None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass
|
|
121
|
+
class ExecutionState:
|
|
122
|
+
"""Current state of the execution for queries"""
|
|
123
|
+
status: str # "pending", "running", "waiting_for_input", "paused", "completed", "failed"
|
|
124
|
+
messages: List[ChatMessage] = field(default_factory=list)
|
|
125
|
+
current_response: str = ""
|
|
126
|
+
error_message: Optional[str] = None
|
|
127
|
+
usage: Dict[str, Any] = field(default_factory=dict)
|
|
128
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
129
|
+
is_waiting_for_input: bool = False
|
|
130
|
+
should_complete: bool = False
|
|
131
|
+
is_paused: bool = False
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@workflow.defn
|
|
135
|
+
class AgentExecutionWorkflow:
|
|
136
|
+
"""
|
|
137
|
+
Workflow for executing an agent with LLM with Temporal message passing support.
|
|
138
|
+
|
|
139
|
+
This workflow:
|
|
140
|
+
1. Updates execution status to running
|
|
141
|
+
2. Executes the agent's LLM call
|
|
142
|
+
3. Updates execution with results
|
|
143
|
+
4. Updates agent status
|
|
144
|
+
5. Supports queries for real-time state access
|
|
145
|
+
6. Supports signals for adding followup messages
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
def __init__(self) -> None:
|
|
149
|
+
"""Initialize workflow state"""
|
|
150
|
+
self._state = ExecutionState(status="pending")
|
|
151
|
+
self._lock = asyncio.Lock()
|
|
152
|
+
self._new_message_count = 0
|
|
153
|
+
self._processed_message_count = 0
|
|
154
|
+
|
|
155
|
+
@workflow.query
|
|
156
|
+
def get_state(self) -> ExecutionState:
|
|
157
|
+
"""Query handler: Get current execution state including messages and status"""
|
|
158
|
+
return self._state
|
|
159
|
+
|
|
160
|
+
@workflow.signal
|
|
161
|
+
async def add_message(self, message: ChatMessage) -> None:
|
|
162
|
+
"""
|
|
163
|
+
Signal handler: Add a message to the conversation.
|
|
164
|
+
This allows clients to send followup messages while the workflow is running.
|
|
165
|
+
The workflow will wake up and process this message.
|
|
166
|
+
"""
|
|
167
|
+
async with self._lock:
|
|
168
|
+
self._state.messages.append(message)
|
|
169
|
+
self._new_message_count += 1
|
|
170
|
+
self._state.is_waiting_for_input = False
|
|
171
|
+
workflow.logger.info(
|
|
172
|
+
f"Message added to conversation",
|
|
173
|
+
extra={
|
|
174
|
+
"role": message.role,
|
|
175
|
+
"content_preview": message.content[:100] if message.content else "",
|
|
176
|
+
"total_messages": len(self._state.messages)
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
@workflow.signal
|
|
181
|
+
async def mark_as_done(self) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Signal handler: Mark the workflow as complete.
|
|
184
|
+
This signals that the user is done with the conversation and the workflow should complete.
|
|
185
|
+
"""
|
|
186
|
+
async with self._lock:
|
|
187
|
+
self._state.should_complete = True
|
|
188
|
+
self._state.is_waiting_for_input = False
|
|
189
|
+
workflow.logger.info("Workflow marked as done by user")
|
|
190
|
+
|
|
191
|
+
@workflow.signal
|
|
192
|
+
async def pause_execution(self) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Signal handler: Pause the workflow execution.
|
|
195
|
+
This pauses the workflow - it will stop processing but remain active.
|
|
196
|
+
Resume can be called to continue execution.
|
|
197
|
+
"""
|
|
198
|
+
async with self._lock:
|
|
199
|
+
if not self._state.is_paused:
|
|
200
|
+
self._state.is_paused = True
|
|
201
|
+
self._state.status = "paused"
|
|
202
|
+
workflow.logger.info("Workflow paused by user")
|
|
203
|
+
|
|
204
|
+
@workflow.signal
|
|
205
|
+
async def resume_execution(self) -> None:
|
|
206
|
+
"""
|
|
207
|
+
Signal handler: Resume a paused workflow execution.
|
|
208
|
+
This resumes the workflow from where it was paused.
|
|
209
|
+
"""
|
|
210
|
+
async with self._lock:
|
|
211
|
+
if self._state.is_paused:
|
|
212
|
+
self._state.is_paused = False
|
|
213
|
+
# Restore previous status (either running or waiting_for_input)
|
|
214
|
+
self._state.status = "waiting_for_input" if self._state.is_waiting_for_input else "running"
|
|
215
|
+
workflow.logger.info("Workflow resumed by user")
|
|
216
|
+
|
|
217
|
+
@workflow.run
|
|
218
|
+
async def run(self, input: AgentExecutionInput) -> dict:
|
|
219
|
+
"""
|
|
220
|
+
Run the agent execution workflow with Human-in-the-Loop (HITL) pattern.
|
|
221
|
+
|
|
222
|
+
This workflow implements a continuous conversation loop:
|
|
223
|
+
1. Process the initial user message
|
|
224
|
+
2. Execute LLM and return response
|
|
225
|
+
3. Wait for user input (signals)
|
|
226
|
+
4. Process followup messages in a loop
|
|
227
|
+
5. Only complete when user explicitly marks as done
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
input: Workflow input with execution details
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Execution result dict with response, usage, etc.
|
|
234
|
+
"""
|
|
235
|
+
workflow.logger.info(
|
|
236
|
+
f"Starting agent execution workflow with HITL pattern",
|
|
237
|
+
extra={
|
|
238
|
+
"execution_id": input.execution_id,
|
|
239
|
+
"agent_id": input.agent_id,
|
|
240
|
+
"organization_id": input.organization_id,
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Initialize state with user's initial message
|
|
245
|
+
self._state.messages.append(ChatMessage(
|
|
246
|
+
role="user",
|
|
247
|
+
content=input.prompt,
|
|
248
|
+
timestamp=workflow.now().isoformat(),
|
|
249
|
+
))
|
|
250
|
+
self._state.status = "running"
|
|
251
|
+
self._new_message_count = 1 # Initial message counts as a new message
|
|
252
|
+
self._processed_message_count = 0 # No messages processed yet (no response)
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
# Step 1: Update execution status to running
|
|
256
|
+
await workflow.execute_activity(
|
|
257
|
+
update_execution_status,
|
|
258
|
+
ActivityUpdateExecutionInput(
|
|
259
|
+
execution_id=input.execution_id,
|
|
260
|
+
status="running",
|
|
261
|
+
started_at=workflow.now().isoformat(),
|
|
262
|
+
execution_metadata={
|
|
263
|
+
"workflow_started": True,
|
|
264
|
+
"has_mcp_servers": bool(input.mcp_servers),
|
|
265
|
+
"mcp_server_count": len(input.mcp_servers) if input.mcp_servers else 0,
|
|
266
|
+
"hitl_enabled": True,
|
|
267
|
+
},
|
|
268
|
+
),
|
|
269
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Step 2: Update agent status to running
|
|
273
|
+
await workflow.execute_activity(
|
|
274
|
+
update_agent_status,
|
|
275
|
+
ActivityUpdateAgentInput(
|
|
276
|
+
agent_id=input.agent_id,
|
|
277
|
+
organization_id=input.organization_id,
|
|
278
|
+
status="running",
|
|
279
|
+
last_active_at=workflow.now().isoformat(),
|
|
280
|
+
),
|
|
281
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
# HITL Conversation Loop - Continue until user marks as done
|
|
285
|
+
conversation_turn = 0
|
|
286
|
+
while not self._state.should_complete:
|
|
287
|
+
# Check if workflow is paused - wait until resumed
|
|
288
|
+
if self._state.is_paused:
|
|
289
|
+
workflow.logger.info("Workflow is paused, waiting for resume signal")
|
|
290
|
+
await workflow.wait_condition(
|
|
291
|
+
lambda: not self._state.is_paused or self._state.should_complete,
|
|
292
|
+
timeout=timedelta(hours=24)
|
|
293
|
+
)
|
|
294
|
+
if self._state.should_complete:
|
|
295
|
+
break
|
|
296
|
+
workflow.logger.info("Workflow resumed, continuing execution")
|
|
297
|
+
|
|
298
|
+
conversation_turn += 1
|
|
299
|
+
|
|
300
|
+
workflow.logger.info(
|
|
301
|
+
f"Starting conversation turn {conversation_turn}",
|
|
302
|
+
extra={"turn": conversation_turn, "message_count": len(self._state.messages)}
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
# Get the latest user message (last message added)
|
|
306
|
+
latest_message = self._state.messages[-1] if self._state.messages else None
|
|
307
|
+
latest_prompt = latest_message.content if latest_message and latest_message.role == "user" else input.prompt
|
|
308
|
+
|
|
309
|
+
# Execute agent LLM call with session_id - Agno handles conversation history automatically
|
|
310
|
+
llm_result = await workflow.execute_activity(
|
|
311
|
+
execute_agent_llm,
|
|
312
|
+
ActivityExecuteAgentInput(
|
|
313
|
+
execution_id=input.execution_id,
|
|
314
|
+
agent_id=input.agent_id,
|
|
315
|
+
organization_id=input.organization_id,
|
|
316
|
+
prompt=latest_prompt, # Current turn's prompt
|
|
317
|
+
system_prompt=input.system_prompt,
|
|
318
|
+
model_id=input.model_id,
|
|
319
|
+
model_config=input.model_config,
|
|
320
|
+
mcp_servers=input.mcp_servers,
|
|
321
|
+
session_id=input.execution_id, # Use execution_id as session_id for 1:1 mapping
|
|
322
|
+
user_id=input.user_metadata.get("user_id") if input.user_metadata else None,
|
|
323
|
+
control_plane_url=input.control_plane_url, # Pass Control Plane URL from workflow input
|
|
324
|
+
api_key=input.api_key, # Pass API key from workflow input
|
|
325
|
+
graph_api_url=input.graph_api_url, # Pass graph API URL for memory tools
|
|
326
|
+
dataset_name=input.dataset_name, # Pass dataset name for memory scoping
|
|
327
|
+
),
|
|
328
|
+
start_to_close_timeout=timedelta(minutes=10),
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
# Update state with assistant response
|
|
332
|
+
if llm_result.get("response"):
|
|
333
|
+
async with self._lock:
|
|
334
|
+
self._state.messages.append(ChatMessage(
|
|
335
|
+
role="assistant",
|
|
336
|
+
content=llm_result["response"],
|
|
337
|
+
timestamp=workflow.now().isoformat(),
|
|
338
|
+
))
|
|
339
|
+
self._state.current_response = llm_result["response"]
|
|
340
|
+
self._processed_message_count += 1
|
|
341
|
+
|
|
342
|
+
# Update usage and metadata (accumulate across turns)
|
|
343
|
+
if llm_result.get("usage"):
|
|
344
|
+
# Accumulate token usage across conversation turns
|
|
345
|
+
current_usage = self._state.usage
|
|
346
|
+
new_usage = llm_result.get("usage", {})
|
|
347
|
+
self._state.usage = {
|
|
348
|
+
"prompt_tokens": current_usage.get("prompt_tokens", 0) + new_usage.get("prompt_tokens", 0),
|
|
349
|
+
"completion_tokens": current_usage.get("completion_tokens", 0) + new_usage.get("completion_tokens", 0),
|
|
350
|
+
"total_tokens": current_usage.get("total_tokens", 0) + new_usage.get("total_tokens", 0),
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
# Update metadata with latest turn info
|
|
354
|
+
self._state.metadata.update({
|
|
355
|
+
"model": llm_result.get("model"),
|
|
356
|
+
"latest_finish_reason": llm_result.get("finish_reason"),
|
|
357
|
+
"mcp_tools_used": self._state.metadata.get("mcp_tools_used", 0) + llm_result.get("mcp_tools_used", 0),
|
|
358
|
+
"latest_run_id": llm_result.get("run_id"),
|
|
359
|
+
"conversation_turns": conversation_turn,
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
# Check if LLM call failed
|
|
363
|
+
if not llm_result.get("success"):
|
|
364
|
+
self._state.status = "failed"
|
|
365
|
+
self._state.error_message = llm_result.get("error")
|
|
366
|
+
break
|
|
367
|
+
|
|
368
|
+
# Update execution status to waiting_for_input
|
|
369
|
+
self._state.status = "waiting_for_input"
|
|
370
|
+
self._state.is_waiting_for_input = True
|
|
371
|
+
|
|
372
|
+
# Update database to reflect waiting state
|
|
373
|
+
await workflow.execute_activity(
|
|
374
|
+
update_execution_status,
|
|
375
|
+
ActivityUpdateExecutionInput(
|
|
376
|
+
execution_id=input.execution_id,
|
|
377
|
+
status="waiting_for_input",
|
|
378
|
+
response=self._state.current_response,
|
|
379
|
+
usage=self._state.usage,
|
|
380
|
+
execution_metadata={
|
|
381
|
+
**self._state.metadata,
|
|
382
|
+
"conversation_turns": conversation_turn,
|
|
383
|
+
"waiting_for_user": True,
|
|
384
|
+
},
|
|
385
|
+
),
|
|
386
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
workflow.logger.info(
|
|
390
|
+
f"Waiting for user input after turn {conversation_turn}",
|
|
391
|
+
extra={"turn": conversation_turn}
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
# Wait for either:
|
|
395
|
+
# 1. New message from user (add_message signal)
|
|
396
|
+
# 2. User marks as done (mark_as_done signal)
|
|
397
|
+
# 3. User pauses execution (pause_execution signal)
|
|
398
|
+
# 4. Timeout (24 hours for long-running conversations)
|
|
399
|
+
await workflow.wait_condition(
|
|
400
|
+
lambda: self._new_message_count > self._processed_message_count or self._state.should_complete or self._state.is_paused,
|
|
401
|
+
timeout=timedelta(hours=24)
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# Don't update processed count here - it will be updated after we add the assistant's response
|
|
405
|
+
|
|
406
|
+
if self._state.should_complete:
|
|
407
|
+
workflow.logger.info("User marked workflow as done")
|
|
408
|
+
break
|
|
409
|
+
|
|
410
|
+
# If paused while waiting, loop back to check pause condition at top of while loop
|
|
411
|
+
if self._state.is_paused:
|
|
412
|
+
workflow.logger.info("Workflow paused while waiting for input")
|
|
413
|
+
continue
|
|
414
|
+
|
|
415
|
+
# Continue loop to process new message
|
|
416
|
+
self._state.status = "running"
|
|
417
|
+
|
|
418
|
+
# Conversation complete - finalize workflow
|
|
419
|
+
final_status = "failed" if self._state.status == "failed" else "completed"
|
|
420
|
+
self._state.status = final_status
|
|
421
|
+
|
|
422
|
+
await workflow.execute_activity(
|
|
423
|
+
update_execution_status,
|
|
424
|
+
ActivityUpdateExecutionInput(
|
|
425
|
+
execution_id=input.execution_id,
|
|
426
|
+
status=final_status,
|
|
427
|
+
completed_at=workflow.now().isoformat(),
|
|
428
|
+
response=self._state.current_response,
|
|
429
|
+
error_message=self._state.error_message,
|
|
430
|
+
usage=self._state.usage,
|
|
431
|
+
execution_metadata={
|
|
432
|
+
**self._state.metadata,
|
|
433
|
+
"workflow_completed": True,
|
|
434
|
+
"total_conversation_turns": conversation_turn,
|
|
435
|
+
},
|
|
436
|
+
),
|
|
437
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
# Update agent final status
|
|
441
|
+
agent_final_status = "completed" if final_status == "completed" else "failed"
|
|
442
|
+
await workflow.execute_activity(
|
|
443
|
+
update_agent_status,
|
|
444
|
+
ActivityUpdateAgentInput(
|
|
445
|
+
agent_id=input.agent_id,
|
|
446
|
+
organization_id=input.organization_id,
|
|
447
|
+
status=agent_final_status,
|
|
448
|
+
last_active_at=workflow.now().isoformat(),
|
|
449
|
+
error_message=self._state.error_message if final_status == "failed" else None,
|
|
450
|
+
),
|
|
451
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
workflow.logger.info(
|
|
455
|
+
f"Agent execution workflow completed with HITL",
|
|
456
|
+
extra={
|
|
457
|
+
"execution_id": input.execution_id,
|
|
458
|
+
"status": final_status,
|
|
459
|
+
"conversation_turns": conversation_turn,
|
|
460
|
+
}
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
"success": final_status == "completed",
|
|
465
|
+
"execution_id": input.execution_id,
|
|
466
|
+
"status": final_status,
|
|
467
|
+
"response": self._state.current_response,
|
|
468
|
+
"usage": self._state.usage,
|
|
469
|
+
"conversation_turns": conversation_turn,
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
except Exception as e:
|
|
473
|
+
# Update state with error
|
|
474
|
+
self._state.status = "failed"
|
|
475
|
+
self._state.error_message = str(e)
|
|
476
|
+
self._state.metadata["error_type"] = type(e).__name__
|
|
477
|
+
|
|
478
|
+
workflow.logger.error(
|
|
479
|
+
f"Agent execution workflow failed",
|
|
480
|
+
extra={
|
|
481
|
+
"execution_id": input.execution_id,
|
|
482
|
+
"error": str(e),
|
|
483
|
+
}
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
# Update execution as failed
|
|
487
|
+
try:
|
|
488
|
+
await workflow.execute_activity(
|
|
489
|
+
update_execution_status,
|
|
490
|
+
ActivityUpdateExecutionInput(
|
|
491
|
+
execution_id=input.execution_id,
|
|
492
|
+
status="failed",
|
|
493
|
+
completed_at=workflow.now().isoformat(),
|
|
494
|
+
error_message=f"Workflow error: {str(e)}",
|
|
495
|
+
execution_metadata={
|
|
496
|
+
"workflow_error": True,
|
|
497
|
+
"error_type": type(e).__name__,
|
|
498
|
+
},
|
|
499
|
+
),
|
|
500
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
await workflow.execute_activity(
|
|
504
|
+
update_agent_status,
|
|
505
|
+
ActivityUpdateAgentInput(
|
|
506
|
+
agent_id=input.agent_id,
|
|
507
|
+
organization_id=input.organization_id,
|
|
508
|
+
status="failed",
|
|
509
|
+
last_active_at=workflow.now().isoformat(),
|
|
510
|
+
error_message=str(e),
|
|
511
|
+
),
|
|
512
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
513
|
+
)
|
|
514
|
+
except Exception as update_error:
|
|
515
|
+
workflow.logger.error(
|
|
516
|
+
f"Failed to update status after error",
|
|
517
|
+
extra={"error": str(update_error)}
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
raise
|