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,793 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Refactored Agent executor service using runtime abstraction.
|
|
3
|
+
|
|
4
|
+
This version delegates execution to pluggable runtime implementations,
|
|
5
|
+
making the code more maintainable and extensible.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Any, Optional, List
|
|
9
|
+
import structlog
|
|
10
|
+
import time
|
|
11
|
+
import os
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
|
|
14
|
+
from control_plane_api.worker.control_plane_client import ControlPlaneClient
|
|
15
|
+
from control_plane_api.worker.services.session_service import SessionService
|
|
16
|
+
from control_plane_api.worker.services.cancellation_manager import CancellationManager
|
|
17
|
+
from control_plane_api.worker.services.analytics_service import AnalyticsService
|
|
18
|
+
from control_plane_api.worker.services.runtime_analytics import submit_runtime_analytics
|
|
19
|
+
from control_plane_api.worker.runtimes import (
|
|
20
|
+
RuntimeFactory,
|
|
21
|
+
RuntimeType,
|
|
22
|
+
RuntimeExecutionContext,
|
|
23
|
+
)
|
|
24
|
+
from control_plane_api.worker.utils.streaming_utils import StreamingHelper
|
|
25
|
+
from control_plane_api.app.lib.templating.types import TemplateContext
|
|
26
|
+
from control_plane_api.app.lib.templating.resolver import resolve_templates
|
|
27
|
+
from control_plane_api.worker.utils.logging_config import sanitize_value
|
|
28
|
+
|
|
29
|
+
logger = structlog.get_logger()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AgentExecutorServiceV2:
|
|
33
|
+
"""
|
|
34
|
+
Service for executing agents using runtime abstraction.
|
|
35
|
+
|
|
36
|
+
This service orchestrates agent execution by:
|
|
37
|
+
1. Loading session history
|
|
38
|
+
2. Selecting appropriate runtime based on agent config
|
|
39
|
+
3. Delegating execution to the runtime
|
|
40
|
+
4. Persisting session after execution
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
control_plane: ControlPlaneClient,
|
|
46
|
+
session_service: SessionService,
|
|
47
|
+
cancellation_manager: CancellationManager,
|
|
48
|
+
):
|
|
49
|
+
"""
|
|
50
|
+
Initialize the agent executor service.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
control_plane: Control Plane API client
|
|
54
|
+
session_service: Session management service
|
|
55
|
+
cancellation_manager: Execution cancellation manager
|
|
56
|
+
"""
|
|
57
|
+
self.control_plane = control_plane
|
|
58
|
+
self.session_service = session_service
|
|
59
|
+
self.cancellation_manager = cancellation_manager
|
|
60
|
+
self.runtime_factory = RuntimeFactory()
|
|
61
|
+
|
|
62
|
+
# Initialize analytics service for tracking LLM usage, tool calls, etc.
|
|
63
|
+
control_plane_url = os.getenv("CONTROL_PLANE_URL", "http://localhost:8000")
|
|
64
|
+
api_key = os.getenv("KUBIYA_API_KEY", "")
|
|
65
|
+
self.analytics_service = AnalyticsService(control_plane_url, api_key)
|
|
66
|
+
|
|
67
|
+
async def execute(self, input: Any) -> Dict[str, Any]:
|
|
68
|
+
"""
|
|
69
|
+
Execute an agent using the configured runtime.
|
|
70
|
+
|
|
71
|
+
This method:
|
|
72
|
+
1. Loads session history
|
|
73
|
+
2. Determines runtime type from agent config
|
|
74
|
+
3. Creates runtime instance
|
|
75
|
+
4. Executes agent via runtime
|
|
76
|
+
5. Persists session
|
|
77
|
+
6. Returns standardized result
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
input: AgentExecutionInput with execution details
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Dict with response, usage, success flag, runtime_type, etc.
|
|
84
|
+
"""
|
|
85
|
+
execution_id = input.execution_id
|
|
86
|
+
|
|
87
|
+
# print("\n" + "=" * 80)
|
|
88
|
+
# print("=" * 80)
|
|
89
|
+
# print(f"Execution ID: {execution_id}")
|
|
90
|
+
# print(f"Agent ID: {input.agent_id}")
|
|
91
|
+
# print(f"Organization: {input.organization_id}")
|
|
92
|
+
# print(f"Model: {input.model_id or 'default'}")
|
|
93
|
+
# print(f"Session ID: {input.session_id}")
|
|
94
|
+
# print(
|
|
95
|
+
# f"Prompt: {input.prompt[:100]}..."
|
|
96
|
+
# if len(input.prompt) > 100
|
|
97
|
+
# else f"Prompt: {input.prompt}"
|
|
98
|
+
# )
|
|
99
|
+
# print("=" * 80 + "\n")
|
|
100
|
+
|
|
101
|
+
logger.info(
|
|
102
|
+
"agent_workflow_start",
|
|
103
|
+
execution_id=execution_id[:8],
|
|
104
|
+
agent_id=input.agent_id,
|
|
105
|
+
organization_id=input.organization_id,
|
|
106
|
+
model=input.model_id or "default",
|
|
107
|
+
session_id=input.session_id,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
# Capture timestamp at start of execution for accurate user message timestamp
|
|
112
|
+
from datetime import datetime, timezone
|
|
113
|
+
user_message_timestamp = datetime.now(timezone.utc).isoformat()
|
|
114
|
+
|
|
115
|
+
# STEP 1: Load session history
|
|
116
|
+
logger.info("loading_session_history", session_id=input.session_id)
|
|
117
|
+
session_history = self.session_service.load_session(
|
|
118
|
+
execution_id=execution_id, session_id=input.session_id
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if session_history:
|
|
122
|
+
# print(f"✅ Loaded {len(session_history)} messages from previous session\n")
|
|
123
|
+
pass
|
|
124
|
+
else:
|
|
125
|
+
logger.info("starting_new_conversation")
|
|
126
|
+
|
|
127
|
+
# STEP 2: Determine runtime type
|
|
128
|
+
agent_config = input.agent_config or {}
|
|
129
|
+
runtime_type_str = agent_config.get("runtime", "default")
|
|
130
|
+
runtime_type = self.runtime_factory.parse_runtime_type(runtime_type_str)
|
|
131
|
+
|
|
132
|
+
logger.info("runtime_type_selected",
|
|
133
|
+
runtime_type=runtime_type.value,
|
|
134
|
+
framework=self._get_framework_name(runtime_type))
|
|
135
|
+
|
|
136
|
+
logger.info(
|
|
137
|
+
"runtime_selected",
|
|
138
|
+
execution_id=execution_id[:8],
|
|
139
|
+
runtime=runtime_type.value,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# STEP 3: Create runtime instance
|
|
143
|
+
# print(f"⚙️ Creating runtime instance...")
|
|
144
|
+
runtime = self.runtime_factory.create_runtime(
|
|
145
|
+
runtime_type=runtime_type,
|
|
146
|
+
control_plane_client=self.control_plane,
|
|
147
|
+
cancellation_manager=self.cancellation_manager,
|
|
148
|
+
)
|
|
149
|
+
# print(f"✅ Runtime created: {runtime.get_runtime_info()}\n")
|
|
150
|
+
|
|
151
|
+
# STEP 4: Get skills (if runtime supports tools)
|
|
152
|
+
skills = []
|
|
153
|
+
if runtime.supports_tools():
|
|
154
|
+
logger.info("fetching_skills")
|
|
155
|
+
try:
|
|
156
|
+
skill_configs = self.control_plane.get_skills(input.agent_id)
|
|
157
|
+
if skill_configs:
|
|
158
|
+
logger.info("skills_resolved", count=len(skill_configs))
|
|
159
|
+
# Skill details logged in skills_resolved
|
|
160
|
+
# Skill details logged in skills_resolved
|
|
161
|
+
# Skill details logged in skills_resolved
|
|
162
|
+
|
|
163
|
+
# DEBUG: Show full config for workflow_executor skills
|
|
164
|
+
for cfg in skill_configs:
|
|
165
|
+
if cfg.get('type') in ['workflow_executor', 'workflow']:
|
|
166
|
+
logger.debug("workflow_executor_skill_config")
|
|
167
|
+
# print(f" Name: {cfg.get('name')}")
|
|
168
|
+
# print(f" Type: {cfg.get('type')}")
|
|
169
|
+
# Skill details logged in skills_resolved
|
|
170
|
+
# print(f" Config Keys: {list(cfg.get('configuration', {}).keys())}\n")
|
|
171
|
+
|
|
172
|
+
# Always include built-in context_graph_search skill
|
|
173
|
+
builtin_skill_types = {'context_graph_search'}
|
|
174
|
+
existing_skill_types = {cfg.get('type') for cfg in skill_configs}
|
|
175
|
+
|
|
176
|
+
for builtin_type in builtin_skill_types:
|
|
177
|
+
if builtin_type not in existing_skill_types:
|
|
178
|
+
builtin_config = {
|
|
179
|
+
'name': builtin_type,
|
|
180
|
+
'type': builtin_type,
|
|
181
|
+
'enabled': True,
|
|
182
|
+
'configuration': {}
|
|
183
|
+
}
|
|
184
|
+
skill_configs.append(builtin_config)
|
|
185
|
+
logger.info("builtin_skill_included", skill_type=builtin_type)
|
|
186
|
+
|
|
187
|
+
# Import here to avoid circular dependency
|
|
188
|
+
from control_plane_api.worker.services.skill_factory import SkillFactory
|
|
189
|
+
|
|
190
|
+
# Create factory instance for the current runtime
|
|
191
|
+
skill_factory = SkillFactory(runtime_type=runtime_type.value)
|
|
192
|
+
skill_factory.initialize()
|
|
193
|
+
|
|
194
|
+
skills = skill_factory.create_skills_from_list(
|
|
195
|
+
skill_configs, execution_id=execution_id
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
if skills:
|
|
199
|
+
logger.info("skills_instantiated", count=len(skills))
|
|
200
|
+
# Show types of instantiated skills
|
|
201
|
+
skill_types = [type(s).__name__ for s in skills]
|
|
202
|
+
# Skill classes logged in skills_instantiated
|
|
203
|
+
else:
|
|
204
|
+
logger.warning("no_skills_instantiated")
|
|
205
|
+
else:
|
|
206
|
+
logger.warning("no_skills_found")
|
|
207
|
+
# Even if no skills configured, add built-in skills
|
|
208
|
+
skill_configs = []
|
|
209
|
+
builtin_skill_types = {'context_graph_search'}
|
|
210
|
+
|
|
211
|
+
for builtin_type in builtin_skill_types:
|
|
212
|
+
builtin_config = {
|
|
213
|
+
'name': builtin_type,
|
|
214
|
+
'type': builtin_type,
|
|
215
|
+
'enabled': True,
|
|
216
|
+
'configuration': {}
|
|
217
|
+
}
|
|
218
|
+
skill_configs.append(builtin_config)
|
|
219
|
+
logger.info("builtin_skill_included", skill_type=builtin_type)
|
|
220
|
+
|
|
221
|
+
if skill_configs:
|
|
222
|
+
# Import here to avoid circular dependency
|
|
223
|
+
from control_plane_api.worker.services.skill_factory import SkillFactory
|
|
224
|
+
|
|
225
|
+
# Create factory instance for the current runtime
|
|
226
|
+
skill_factory = SkillFactory(runtime_type=runtime_type.value)
|
|
227
|
+
skill_factory.initialize()
|
|
228
|
+
|
|
229
|
+
skills = skill_factory.create_skills_from_list(
|
|
230
|
+
skill_configs, execution_id=execution_id
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
if skills:
|
|
234
|
+
logger.info("skills_instantiated", count=len(skills))
|
|
235
|
+
skill_types = [type(s).__name__ for s in skills]
|
|
236
|
+
# Skill classes logged in skills_instantiated
|
|
237
|
+
except Exception as e:
|
|
238
|
+
logger.warning("skill_fetch_error", error=str(e))
|
|
239
|
+
logger.error("skill_fetch_error", error=str(e), exc_info=True)
|
|
240
|
+
|
|
241
|
+
# STEP 5: Inject environment variables into MCP servers (runtime-agnostic)
|
|
242
|
+
logger.info("fetching_resolved_environment")
|
|
243
|
+
from control_plane_api.worker.activities.runtime_activities import inject_env_vars_into_mcp_servers
|
|
244
|
+
mcp_servers_with_env = inject_env_vars_into_mcp_servers(
|
|
245
|
+
mcp_servers=input.mcp_servers,
|
|
246
|
+
agent_config=agent_config,
|
|
247
|
+
runtime_config=agent_config.get("runtime_config"),
|
|
248
|
+
control_plane_client=self.control_plane,
|
|
249
|
+
agent_id=input.agent_id,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# STEP 6: Compile system prompt templates
|
|
253
|
+
logger.info("compiling_system_prompt_templates")
|
|
254
|
+
compiled_system_prompt = input.system_prompt
|
|
255
|
+
if input.system_prompt:
|
|
256
|
+
try:
|
|
257
|
+
# Build template context with available variables
|
|
258
|
+
template_context = TemplateContext(
|
|
259
|
+
variables=input.user_metadata or {},
|
|
260
|
+
secrets=agent_config.get("secrets", {}),
|
|
261
|
+
env_vars=dict(os.environ), # Make all env vars available
|
|
262
|
+
# Context graph API configuration for {{.graph.node-id}} templates
|
|
263
|
+
graph_api_base=os.environ.get("CONTEXT_GRAPH_API_BASE", "https://graph.kubiya.ai"),
|
|
264
|
+
graph_api_key=os.environ.get("KUBIYA_API_KEY"),
|
|
265
|
+
graph_org_id=os.environ.get("KUBIYA_ORG_ID") or input.organization_id
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Resolve templates in system prompt
|
|
269
|
+
compiled_system_prompt = resolve_templates(
|
|
270
|
+
input.system_prompt,
|
|
271
|
+
template_context,
|
|
272
|
+
strict=False, # Don't fail on missing variables
|
|
273
|
+
skip_on_error=True # Return original if compilation fails
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
if compiled_system_prompt != input.system_prompt:
|
|
277
|
+
logger.info(
|
|
278
|
+
"system_prompt_templates_compiled",
|
|
279
|
+
original_length=len(input.system_prompt),
|
|
280
|
+
compiled_length=len(compiled_system_prompt)
|
|
281
|
+
)
|
|
282
|
+
logger.info("system_prompt_templates_compiled")
|
|
283
|
+
else:
|
|
284
|
+
logger.info("no_templates_in_system_prompt")
|
|
285
|
+
|
|
286
|
+
except Exception as e:
|
|
287
|
+
logger.warning(
|
|
288
|
+
"system_prompt_template_compilation_failed",
|
|
289
|
+
error=str(e),
|
|
290
|
+
exc_info=True
|
|
291
|
+
)
|
|
292
|
+
logger.warning("system_prompt_compilation_failed", error=str(e))
|
|
293
|
+
# Use original system prompt if compilation fails
|
|
294
|
+
compiled_system_prompt = input.system_prompt
|
|
295
|
+
|
|
296
|
+
# STEP 6.5: Enhance system prompt with complete execution environment context
|
|
297
|
+
execution_context_info = self._build_execution_context_info(
|
|
298
|
+
runtime_config=agent_config.get("runtime_config", {}),
|
|
299
|
+
skills=skills,
|
|
300
|
+
mcp_servers=mcp_servers_with_env,
|
|
301
|
+
agent_config=agent_config
|
|
302
|
+
)
|
|
303
|
+
if execution_context_info:
|
|
304
|
+
if compiled_system_prompt:
|
|
305
|
+
compiled_system_prompt = compiled_system_prompt + "\n\n" + execution_context_info
|
|
306
|
+
else:
|
|
307
|
+
compiled_system_prompt = execution_context_info
|
|
308
|
+
logger.info("system_prompt_enhanced")
|
|
309
|
+
|
|
310
|
+
# STEP 7: Build execution context
|
|
311
|
+
logger.info("building_execution_context")
|
|
312
|
+
context = RuntimeExecutionContext(
|
|
313
|
+
execution_id=execution_id,
|
|
314
|
+
agent_id=input.agent_id,
|
|
315
|
+
organization_id=input.organization_id,
|
|
316
|
+
prompt=input.prompt,
|
|
317
|
+
system_prompt=compiled_system_prompt,
|
|
318
|
+
conversation_history=session_history,
|
|
319
|
+
model_id=input.model_id,
|
|
320
|
+
model_config=input.model_config,
|
|
321
|
+
agent_config=agent_config,
|
|
322
|
+
skills=skills,
|
|
323
|
+
skill_configs=skill_configs, # Original skill configurations for prompt enhancement
|
|
324
|
+
mcp_servers=mcp_servers_with_env, # Use MCP servers with injected env vars
|
|
325
|
+
user_metadata=input.user_metadata,
|
|
326
|
+
runtime_config=agent_config.get("runtime_config"),
|
|
327
|
+
)
|
|
328
|
+
logger.info("execution_context_ready")
|
|
329
|
+
|
|
330
|
+
# STEP 7: Publish user message to stream before execution
|
|
331
|
+
# This ensures chronological ordering in UI
|
|
332
|
+
turn_number = len(session_history) // 2 + 1
|
|
333
|
+
user_message_id = f"{execution_id}_user_{turn_number}"
|
|
334
|
+
self.control_plane.publish_event(
|
|
335
|
+
execution_id=execution_id,
|
|
336
|
+
event_type="message",
|
|
337
|
+
data={
|
|
338
|
+
"role": "user",
|
|
339
|
+
"content": input.prompt,
|
|
340
|
+
"timestamp": user_message_timestamp,
|
|
341
|
+
"message_id": user_message_id,
|
|
342
|
+
"user_id": input.user_id,
|
|
343
|
+
"user_name": getattr(input, "user_name", None),
|
|
344
|
+
"user_email": getattr(input, "user_email", None),
|
|
345
|
+
"user_avatar": getattr(input, "user_avatar", None),
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
logger.debug("user_message_published", message_id=user_message_id)
|
|
349
|
+
|
|
350
|
+
# Publish status message chunk: Connecting to worker
|
|
351
|
+
assistant_message_id = f"{execution_id}_assistant_{turn_number}"
|
|
352
|
+
await self.control_plane.publish_event_async(
|
|
353
|
+
execution_id=execution_id,
|
|
354
|
+
event_type="message_chunk",
|
|
355
|
+
data={
|
|
356
|
+
"role": "assistant",
|
|
357
|
+
"content": "Connecting to worker...\n",
|
|
358
|
+
"is_chunk": True,
|
|
359
|
+
"message_id": assistant_message_id,
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
# print(f" 📤 Published status: 'Connecting to worker...'\n")
|
|
363
|
+
|
|
364
|
+
# STEP 8: Execute via runtime (with streaming if supported)
|
|
365
|
+
# print("⚡ Executing via runtime...\n")
|
|
366
|
+
|
|
367
|
+
# Track turn start time for analytics
|
|
368
|
+
turn_start_time = time.time()
|
|
369
|
+
|
|
370
|
+
# Create streaming helper for tracking tool messages (used in both streaming and non-streaming)
|
|
371
|
+
streaming_helper = StreamingHelper(
|
|
372
|
+
control_plane_client=self.control_plane, execution_id=execution_id
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
if runtime.supports_streaming():
|
|
376
|
+
result = await self._execute_streaming(runtime, context, input, streaming_helper)
|
|
377
|
+
else:
|
|
378
|
+
result = await runtime.execute(context)
|
|
379
|
+
|
|
380
|
+
# Track turn end time
|
|
381
|
+
turn_end_time = time.time()
|
|
382
|
+
|
|
383
|
+
# print("\n✅ Runtime execution completed!")
|
|
384
|
+
logger.info("response_length", length=len(result["response"]))
|
|
385
|
+
# print(f" Success: {result.success}\n")
|
|
386
|
+
|
|
387
|
+
logger.info(
|
|
388
|
+
"agent_execution_completed",
|
|
389
|
+
execution_id=execution_id[:8],
|
|
390
|
+
success=result.success,
|
|
391
|
+
response_length=len(result.response),
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
# STEP 7.5: Submit analytics (non-blocking, fire-and-forget)
|
|
395
|
+
if result.success and result.usage:
|
|
396
|
+
try:
|
|
397
|
+
# Submit analytics in the background (doesn't block execution)
|
|
398
|
+
await submit_runtime_analytics(
|
|
399
|
+
result=result,
|
|
400
|
+
execution_id=execution_id,
|
|
401
|
+
turn_number=turn_number,
|
|
402
|
+
turn_start_time=turn_start_time,
|
|
403
|
+
turn_end_time=turn_end_time,
|
|
404
|
+
analytics_service=self.analytics_service,
|
|
405
|
+
)
|
|
406
|
+
logger.info(
|
|
407
|
+
"analytics_submitted",
|
|
408
|
+
execution_id=execution_id[:8],
|
|
409
|
+
tokens=result.usage.get("total_tokens", 0),
|
|
410
|
+
)
|
|
411
|
+
except Exception as analytics_error:
|
|
412
|
+
# Analytics failures should not break execution
|
|
413
|
+
logger.warning(
|
|
414
|
+
"analytics_submission_failed",
|
|
415
|
+
execution_id=execution_id[:8],
|
|
416
|
+
error=str(analytics_error),
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
# STEP 7: Persist session
|
|
420
|
+
if result.success and result.response:
|
|
421
|
+
logger.info("persisting_session_history")
|
|
422
|
+
|
|
423
|
+
# Finalize streaming to transition to post-tool phase
|
|
424
|
+
streaming_helper.finalize_streaming()
|
|
425
|
+
|
|
426
|
+
# Build user message
|
|
427
|
+
user_message = {
|
|
428
|
+
"role": "user",
|
|
429
|
+
"content": input.prompt,
|
|
430
|
+
"timestamp": user_message_timestamp, # Use timestamp from start
|
|
431
|
+
"message_id": f"{execution_id}_user_{turn_number}",
|
|
432
|
+
"user_id": input.user_id,
|
|
433
|
+
"user_name": getattr(input, "user_name", None),
|
|
434
|
+
"user_email": getattr(input, "user_email", None),
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
# Build structured messages using StreamingHelper
|
|
438
|
+
# This properly splits assistant messages around tool usage
|
|
439
|
+
new_messages = streaming_helper.build_structured_messages(
|
|
440
|
+
execution_id=execution_id,
|
|
441
|
+
turn_number=turn_number,
|
|
442
|
+
user_message=user_message,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
logger.debug("structured_messages_built", count=len(new_messages))
|
|
446
|
+
if streaming_helper.has_any_tools:
|
|
447
|
+
logger.debug("assistant_message_split_into_phases")
|
|
448
|
+
assistant_parts = streaming_helper.get_assistant_message_parts()
|
|
449
|
+
for part in assistant_parts:
|
|
450
|
+
logger.debug("message_part", phase=part["phase"], length=len(part["content"]))
|
|
451
|
+
|
|
452
|
+
# Combine with previous history
|
|
453
|
+
complete_session = session_history + new_messages
|
|
454
|
+
|
|
455
|
+
# CRITICAL: Deduplicate messages by message_id AND content to prevent duplicates
|
|
456
|
+
# Use session_service.deduplicate_messages() which has enhanced two-level deduplication
|
|
457
|
+
original_count = len(complete_session)
|
|
458
|
+
complete_session = self.session_service.deduplicate_messages(complete_session)
|
|
459
|
+
deduplicated_count = len(complete_session)
|
|
460
|
+
|
|
461
|
+
# CRITICAL: Sort by timestamp to ensure chronological order
|
|
462
|
+
# Tool messages happen DURING streaming, so they need to be interleaved with user/assistant messages
|
|
463
|
+
complete_session.sort(key=lambda msg: msg.get("timestamp", ""))
|
|
464
|
+
logger.info("messages_deduplicated", before=original_count, after=deduplicated_count, removed=original_count - deduplicated_count)
|
|
465
|
+
|
|
466
|
+
success = self.session_service.persist_session(
|
|
467
|
+
execution_id=execution_id,
|
|
468
|
+
session_id=input.session_id or execution_id,
|
|
469
|
+
user_id=input.user_id,
|
|
470
|
+
messages=complete_session,
|
|
471
|
+
metadata={
|
|
472
|
+
"agent_id": input.agent_id,
|
|
473
|
+
"organization_id": input.organization_id,
|
|
474
|
+
"runtime_type": runtime_type.value,
|
|
475
|
+
"turn_count": len(complete_session),
|
|
476
|
+
},
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
if success:
|
|
480
|
+
# print(f"✅ Session persisted ({len(complete_session)} total messages)\n")
|
|
481
|
+
pass
|
|
482
|
+
else:
|
|
483
|
+
logger.warning("session_persistence_failed")
|
|
484
|
+
|
|
485
|
+
# STEP 8: Print usage metrics
|
|
486
|
+
if result.usage:
|
|
487
|
+
logger.info("token_usage",
|
|
488
|
+
prompt_tokens=result["usage"].get("prompt_tokens", 0),
|
|
489
|
+
completion_tokens=result["usage"].get("completion_tokens", 0),
|
|
490
|
+
total_tokens=result["usage"].get("total_tokens", 0))
|
|
491
|
+
|
|
492
|
+
# print("=" * 80)
|
|
493
|
+
logger.info("agent_execution_end")
|
|
494
|
+
# print("=" * 80 + "\n")
|
|
495
|
+
|
|
496
|
+
# Return standardized result
|
|
497
|
+
return {
|
|
498
|
+
"success": result.success,
|
|
499
|
+
"response": result.response,
|
|
500
|
+
"usage": result.usage,
|
|
501
|
+
"model": result.model or input.model_id,
|
|
502
|
+
"finish_reason": result.finish_reason or "stop",
|
|
503
|
+
"run_id": result.run_id,
|
|
504
|
+
"tool_messages": result.tool_messages or [],
|
|
505
|
+
"runtime_type": runtime_type.value,
|
|
506
|
+
"error": result.error,
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
except Exception as e:
|
|
510
|
+
# print("\n" + "=" * 80)
|
|
511
|
+
logger.error("agent_execution_failed")
|
|
512
|
+
# print("=" * 80)
|
|
513
|
+
logger.error("execution_error", error=str(e))
|
|
514
|
+
# print("=" * 80 + "\n")
|
|
515
|
+
|
|
516
|
+
logger.error(
|
|
517
|
+
"agent_execution_failed", execution_id=execution_id[:8], error=str(e)
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Publish critical error as message to the stream
|
|
521
|
+
try:
|
|
522
|
+
error_message = f"❌ Critical Error: {str(e)}"
|
|
523
|
+
turn_number = len(session_history) // 2 + 1 if "session_history" in locals() else 1
|
|
524
|
+
assistant_message_id = f"{execution_id}_assistant_{turn_number}"
|
|
525
|
+
|
|
526
|
+
self.control_plane.publish_event(
|
|
527
|
+
execution_id=execution_id,
|
|
528
|
+
event_type="message",
|
|
529
|
+
data={
|
|
530
|
+
"role": "assistant",
|
|
531
|
+
"content": error_message,
|
|
532
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
533
|
+
"message_id": assistant_message_id,
|
|
534
|
+
"is_error": True,
|
|
535
|
+
}
|
|
536
|
+
)
|
|
537
|
+
# print(f" 📤 Published critical error to stream\n")
|
|
538
|
+
except Exception as publish_error:
|
|
539
|
+
# Don't let error publishing break the error handling
|
|
540
|
+
logger.warning(
|
|
541
|
+
"failed_to_publish_error_event",
|
|
542
|
+
execution_id=execution_id[:8],
|
|
543
|
+
error=str(publish_error)
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
"success": False,
|
|
548
|
+
"error": str(e),
|
|
549
|
+
"model": input.model_id,
|
|
550
|
+
"usage": {},
|
|
551
|
+
"finish_reason": "error",
|
|
552
|
+
"runtime_type": runtime_type.value if "runtime_type" in locals() else "unknown",
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async def _execute_streaming(
|
|
556
|
+
self, runtime, context: RuntimeExecutionContext, input: Any, streaming_helper: StreamingHelper
|
|
557
|
+
) -> Any:
|
|
558
|
+
"""
|
|
559
|
+
Execute with streaming and publish events to Control Plane.
|
|
560
|
+
|
|
561
|
+
Args:
|
|
562
|
+
runtime: Runtime instance
|
|
563
|
+
context: Execution context
|
|
564
|
+
input: Original input for additional metadata
|
|
565
|
+
streaming_helper: StreamingHelper instance for tracking events
|
|
566
|
+
|
|
567
|
+
Returns:
|
|
568
|
+
Final RuntimeExecutionResult
|
|
569
|
+
"""
|
|
570
|
+
# streaming_helper is now passed as parameter instead of created here
|
|
571
|
+
|
|
572
|
+
accumulated_response = ""
|
|
573
|
+
final_result = None
|
|
574
|
+
|
|
575
|
+
# Define event callback for publishing to Control Plane
|
|
576
|
+
def event_callback(event: Dict):
|
|
577
|
+
"""Callback to publish events to Control Plane SSE"""
|
|
578
|
+
event_type = event.get("type")
|
|
579
|
+
|
|
580
|
+
if event_type == "content_chunk":
|
|
581
|
+
# Publish content chunk
|
|
582
|
+
streaming_helper.publish_content_chunk(
|
|
583
|
+
content=event.get("content", ""),
|
|
584
|
+
message_id=event.get("message_id", context.execution_id),
|
|
585
|
+
)
|
|
586
|
+
elif event_type == "tool_start":
|
|
587
|
+
# Publish tool start
|
|
588
|
+
streaming_helper.publish_tool_start(
|
|
589
|
+
tool_name=event.get("tool_name"),
|
|
590
|
+
tool_execution_id=event.get("tool_execution_id"),
|
|
591
|
+
tool_args=event.get("tool_args", {}),
|
|
592
|
+
source="agent",
|
|
593
|
+
)
|
|
594
|
+
elif event_type == "tool_complete":
|
|
595
|
+
# Publish tool completion
|
|
596
|
+
streaming_helper.publish_tool_complete(
|
|
597
|
+
tool_name=event.get("tool_name"),
|
|
598
|
+
tool_execution_id=event.get("tool_execution_id"),
|
|
599
|
+
status=event.get("status", "success"),
|
|
600
|
+
output=event.get("output"),
|
|
601
|
+
error=event.get("error"),
|
|
602
|
+
source="agent",
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
# Stream execution
|
|
606
|
+
async for chunk in runtime.stream_execute(context, event_callback):
|
|
607
|
+
if chunk.response:
|
|
608
|
+
accumulated_response += chunk.response
|
|
609
|
+
# print(chunk.response, end="", flush=True)
|
|
610
|
+
|
|
611
|
+
# Keep final result for metadata
|
|
612
|
+
if chunk.usage or chunk.finish_reason:
|
|
613
|
+
final_result = chunk
|
|
614
|
+
|
|
615
|
+
# Empty line removed
|
|
616
|
+
|
|
617
|
+
# Return final result with accumulated response
|
|
618
|
+
if final_result:
|
|
619
|
+
# Update response with accumulated content
|
|
620
|
+
final_result.response = accumulated_response
|
|
621
|
+
return final_result
|
|
622
|
+
else:
|
|
623
|
+
# Create final result if not provided
|
|
624
|
+
from runtimes.base import RuntimeExecutionResult
|
|
625
|
+
|
|
626
|
+
return RuntimeExecutionResult(
|
|
627
|
+
response=accumulated_response,
|
|
628
|
+
usage={},
|
|
629
|
+
success=True,
|
|
630
|
+
finish_reason="stop",
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
def _build_execution_context_info(
|
|
634
|
+
self,
|
|
635
|
+
runtime_config: Dict[str, Any],
|
|
636
|
+
skills: List[Any],
|
|
637
|
+
mcp_servers: Optional[Dict[str, Any]],
|
|
638
|
+
agent_config: Dict[str, Any]
|
|
639
|
+
) -> str:
|
|
640
|
+
"""
|
|
641
|
+
Build comprehensive execution environment context for system prompt.
|
|
642
|
+
|
|
643
|
+
This provides the agent with awareness of:
|
|
644
|
+
- Available environment variables (secrets, integrations, config)
|
|
645
|
+
- Available skills/tools
|
|
646
|
+
- MCP servers
|
|
647
|
+
- Runtime configuration
|
|
648
|
+
|
|
649
|
+
Args:
|
|
650
|
+
runtime_config: Runtime configuration with env vars
|
|
651
|
+
skills: List of available skills
|
|
652
|
+
mcp_servers: Dictionary of MCP server configurations
|
|
653
|
+
agent_config: Agent configuration
|
|
654
|
+
|
|
655
|
+
Returns:
|
|
656
|
+
Formatted execution context string for system prompt
|
|
657
|
+
"""
|
|
658
|
+
context_parts = []
|
|
659
|
+
context_parts.append("---")
|
|
660
|
+
context_parts.append("")
|
|
661
|
+
context_parts.append("# 🔧 Execution Environment Context")
|
|
662
|
+
context_parts.append("")
|
|
663
|
+
context_parts.append("You are running in a managed execution environment with the following resources available:")
|
|
664
|
+
context_parts.append("")
|
|
665
|
+
|
|
666
|
+
# 1. Environment Variables
|
|
667
|
+
if runtime_config and "env" in runtime_config:
|
|
668
|
+
available_env_vars = runtime_config["env"]
|
|
669
|
+
|
|
670
|
+
# Categorize environment variables
|
|
671
|
+
secrets = [k for k in available_env_vars.keys() if any(
|
|
672
|
+
keyword in k.lower()
|
|
673
|
+
for keyword in ["secret", "password", "credential", "api_key", "private_key"]
|
|
674
|
+
) and k not in ["KUBIYA_API_KEY", "KUBIYA_API_BASE", "ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL"]]
|
|
675
|
+
|
|
676
|
+
integrations = [k for k in available_env_vars.keys() if any(
|
|
677
|
+
prefix in k
|
|
678
|
+
for prefix in ["GH_TOKEN", "GITHUB_", "JIRA_", "SLACK_", "AWS_", "GCP_", "AZURE_"]
|
|
679
|
+
)]
|
|
680
|
+
|
|
681
|
+
inherited_vars = [k for k in available_env_vars.keys()
|
|
682
|
+
if k not in secrets
|
|
683
|
+
and k not in integrations
|
|
684
|
+
and k not in ["KUBIYA_API_KEY", "KUBIYA_API_BASE", "ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL", "LITELLM_API_KEY", "LITELLM_API_BASE"]]
|
|
685
|
+
|
|
686
|
+
context_parts.append("## 📦 Environment Variables")
|
|
687
|
+
context_parts.append("")
|
|
688
|
+
|
|
689
|
+
if secrets:
|
|
690
|
+
context_parts.append("**Secrets & API Keys** (use these for authenticated operations):")
|
|
691
|
+
for var in sorted(secrets):
|
|
692
|
+
context_parts.append(f"- `${var}` - Secret/credential available as environment variable")
|
|
693
|
+
context_parts.append("")
|
|
694
|
+
|
|
695
|
+
if integrations:
|
|
696
|
+
context_parts.append("**Integration Tokens** (pre-configured service access):")
|
|
697
|
+
for var in sorted(integrations):
|
|
698
|
+
service = var.split("_")[0].title() if "_" in var else var
|
|
699
|
+
context_parts.append(f"- `${var}` - {service} integration token")
|
|
700
|
+
context_parts.append("")
|
|
701
|
+
|
|
702
|
+
if inherited_vars:
|
|
703
|
+
context_parts.append("**Configuration Variables** (inherited from environment):")
|
|
704
|
+
# Limit to first 10 to avoid clutter
|
|
705
|
+
for var in sorted(inherited_vars)[:10]:
|
|
706
|
+
context_parts.append(f"- `${var}`")
|
|
707
|
+
if len(inherited_vars) > 10:
|
|
708
|
+
context_parts.append(f"- ... and {len(inherited_vars) - 10} more")
|
|
709
|
+
context_parts.append("")
|
|
710
|
+
|
|
711
|
+
if secrets or integrations or inherited_vars:
|
|
712
|
+
context_parts.append("**Usage Examples:**")
|
|
713
|
+
context_parts.append("```bash")
|
|
714
|
+
context_parts.append("# Access in Bash commands")
|
|
715
|
+
context_parts.append("echo $VARIABLE_NAME")
|
|
716
|
+
context_parts.append("")
|
|
717
|
+
if integrations:
|
|
718
|
+
example_token = sorted(integrations)[0]
|
|
719
|
+
if "GH" in example_token or "GITHUB" in example_token:
|
|
720
|
+
context_parts.append("# Use with GitHub API")
|
|
721
|
+
context_parts.append(f"curl -H \"Authorization: token ${example_token}\" https://api.github.com/user")
|
|
722
|
+
elif "JIRA" in example_token:
|
|
723
|
+
context_parts.append("# Use with Jira API")
|
|
724
|
+
context_parts.append(f"curl -H \"Authorization: Bearer ${example_token}\" https://yourinstance.atlassian.net/rest/api/3/myself")
|
|
725
|
+
context_parts.append("```")
|
|
726
|
+
context_parts.append("")
|
|
727
|
+
|
|
728
|
+
# 2. Available Skills/Tools
|
|
729
|
+
if skills:
|
|
730
|
+
context_parts.append("## 🛠️ Available Skills/Tools")
|
|
731
|
+
context_parts.append("")
|
|
732
|
+
skill_names = []
|
|
733
|
+
for skill in skills:
|
|
734
|
+
if isinstance(skill, dict):
|
|
735
|
+
skill_names.append(skill.get("name", skill.get("type", "Unknown")))
|
|
736
|
+
else:
|
|
737
|
+
skill_names.append(type(skill).__name__ if hasattr(skill, '__class__') else str(skill))
|
|
738
|
+
|
|
739
|
+
if skill_names:
|
|
740
|
+
context_parts.append(f"You have access to {len(skill_names)} skill(s):")
|
|
741
|
+
for skill_name in sorted(set(skill_names))[:15]: # Limit to 15 to avoid clutter
|
|
742
|
+
context_parts.append(f"- `{skill_name}`")
|
|
743
|
+
if len(set(skill_names)) > 15:
|
|
744
|
+
context_parts.append(f"- ... and {len(set(skill_names)) - 15} more")
|
|
745
|
+
context_parts.append("")
|
|
746
|
+
|
|
747
|
+
# 3. MCP Servers
|
|
748
|
+
if mcp_servers:
|
|
749
|
+
context_parts.append("## 🔌 MCP Servers")
|
|
750
|
+
context_parts.append("")
|
|
751
|
+
context_parts.append(f"You have access to {len(mcp_servers)} MCP server(s):")
|
|
752
|
+
for server_name in sorted(mcp_servers.keys())[:10]: # Limit to 10
|
|
753
|
+
context_parts.append(f"- `{server_name}`")
|
|
754
|
+
if len(mcp_servers) > 10:
|
|
755
|
+
context_parts.append(f"- ... and {len(mcp_servers) - 10} more")
|
|
756
|
+
context_parts.append("")
|
|
757
|
+
context_parts.append("**Note:** All environment variables listed above are automatically available to these MCP servers.")
|
|
758
|
+
context_parts.append("")
|
|
759
|
+
|
|
760
|
+
# 4. Best Practices
|
|
761
|
+
context_parts.append("## 💡 Best Practices")
|
|
762
|
+
context_parts.append("")
|
|
763
|
+
context_parts.append("- **Environment Variables**: All listed variables are ready to use - no configuration needed")
|
|
764
|
+
context_parts.append("- **Secrets**: Never log or display secret values in responses")
|
|
765
|
+
context_parts.append("- **Integration Tokens**: These provide pre-authorized access to external services")
|
|
766
|
+
context_parts.append("- **MCP Tools**: Prefer using MCP tools over Bash when available for better reliability")
|
|
767
|
+
context_parts.append("")
|
|
768
|
+
context_parts.append("---")
|
|
769
|
+
|
|
770
|
+
logger.info(
|
|
771
|
+
"execution_context_info_built",
|
|
772
|
+
env_vars_count=len(runtime_config.get("env", {})) if runtime_config else 0,
|
|
773
|
+
skills_count=len(skills) if skills else 0,
|
|
774
|
+
mcp_servers_count=len(mcp_servers) if mcp_servers else 0
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
return "\n".join(context_parts)
|
|
778
|
+
|
|
779
|
+
def _get_framework_name(self, runtime_type: RuntimeType) -> str:
|
|
780
|
+
"""
|
|
781
|
+
Get friendly framework name for runtime type.
|
|
782
|
+
|
|
783
|
+
Args:
|
|
784
|
+
runtime_type: Runtime type enum
|
|
785
|
+
|
|
786
|
+
Returns:
|
|
787
|
+
Framework name string
|
|
788
|
+
"""
|
|
789
|
+
mapping = {
|
|
790
|
+
RuntimeType.DEFAULT: "Agno",
|
|
791
|
+
RuntimeType.CLAUDE_CODE: "Claude Code SDK",
|
|
792
|
+
}
|
|
793
|
+
return mapping.get(runtime_type, "Unknown")
|