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,248 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration builder for Agno runtime.
|
|
3
|
+
|
|
4
|
+
This module handles:
|
|
5
|
+
- LiteLLM API configuration
|
|
6
|
+
- Model selection and setup
|
|
7
|
+
- Agent configuration
|
|
8
|
+
- Environment variable management
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import structlog
|
|
13
|
+
from typing import Any, Optional, List
|
|
14
|
+
|
|
15
|
+
from agno.agent import Agent
|
|
16
|
+
from agno.models.litellm import LiteLLM
|
|
17
|
+
from control_plane_api.worker.services.system_prompt_enhancement import create_default_prompt_builder
|
|
18
|
+
from control_plane_api.worker.runtimes.model_utils import get_effective_model, is_model_override_active
|
|
19
|
+
|
|
20
|
+
# Import LiteLLMLangfuse for proper Langfuse metadata support
|
|
21
|
+
try:
|
|
22
|
+
from agno.models.litellm import LiteLLMLangfuse
|
|
23
|
+
LANGFUSE_SUPPORT = True
|
|
24
|
+
except ImportError:
|
|
25
|
+
LANGFUSE_SUPPORT = False
|
|
26
|
+
|
|
27
|
+
logger = structlog.get_logger(__name__)
|
|
28
|
+
|
|
29
|
+
# Module-level singleton for system prompt enhancement
|
|
30
|
+
# NOTE: This is now created per-execution to support dynamic skill context
|
|
31
|
+
# _prompt_builder = create_default_prompt_builder()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def build_agno_agent_config(
|
|
35
|
+
agent_id: str,
|
|
36
|
+
system_prompt: Optional[str] = None,
|
|
37
|
+
model_id: Optional[str] = None,
|
|
38
|
+
skills: Optional[List[Any]] = None,
|
|
39
|
+
mcp_tools: Optional[List[Any]] = None,
|
|
40
|
+
tool_hooks: Optional[List[Any]] = None,
|
|
41
|
+
user_id: Optional[str] = None,
|
|
42
|
+
session_id: Optional[str] = None,
|
|
43
|
+
organization_id: Optional[str] = None,
|
|
44
|
+
agent_name: Optional[str] = None,
|
|
45
|
+
skill_configs: Optional[List[Any]] = None,
|
|
46
|
+
user_metadata: Optional[dict] = None,
|
|
47
|
+
additional_context: Optional[dict] = None,
|
|
48
|
+
) -> Agent:
|
|
49
|
+
"""
|
|
50
|
+
Build Agno Agent configuration with LiteLLM.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
agent_id: Unique identifier for the agent
|
|
54
|
+
system_prompt: System-level instructions
|
|
55
|
+
model_id: Model identifier (overrides default)
|
|
56
|
+
skills: List of skills/tools available to agent
|
|
57
|
+
mcp_tools: List of MCPTools instances
|
|
58
|
+
tool_hooks: List of tool execution hooks
|
|
59
|
+
user_id: User identifier (email) for Langfuse tracking
|
|
60
|
+
session_id: Session identifier for Langfuse tracking
|
|
61
|
+
organization_id: Organization identifier for Langfuse tracking
|
|
62
|
+
agent_name: Agent name for generation naming
|
|
63
|
+
skill_configs: Original skill configuration dictionaries for prompt enhancement
|
|
64
|
+
user_metadata: User metadata dict containing user_id, user_name, user_email, user_avatar
|
|
65
|
+
additional_context: Additional contextual information to inject (custom key-value pairs)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Configured Agno Agent instance
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
ValueError: If required environment variables are missing
|
|
72
|
+
"""
|
|
73
|
+
# Get LiteLLM configuration from environment
|
|
74
|
+
litellm_api_base = os.getenv(
|
|
75
|
+
"LITELLM_API_BASE", "https://llm-proxy.kubiya.ai"
|
|
76
|
+
)
|
|
77
|
+
litellm_api_key = os.getenv("LITELLM_API_KEY")
|
|
78
|
+
|
|
79
|
+
if not litellm_api_key:
|
|
80
|
+
raise ValueError("LITELLM_API_KEY environment variable not set")
|
|
81
|
+
|
|
82
|
+
# Determine model to use with override support
|
|
83
|
+
# Priority: KUBIYA_MODEL_OVERRIDE > model_id > LITELLM_DEFAULT_MODEL > default
|
|
84
|
+
model = get_effective_model(
|
|
85
|
+
context_model_id=model_id,
|
|
86
|
+
log_context={"agent_id": agent_id},
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
logger.info(
|
|
90
|
+
"building_agno_agent_config",
|
|
91
|
+
agent_id=agent_id,
|
|
92
|
+
model=model,
|
|
93
|
+
has_skills=bool(skills),
|
|
94
|
+
has_mcp_tools=bool(mcp_tools),
|
|
95
|
+
mcp_tools_count=len(mcp_tools) if mcp_tools else 0,
|
|
96
|
+
has_tool_hooks=bool(tool_hooks),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Build metadata for Langfuse tracking
|
|
100
|
+
# Format: trace_user_id = EMAIL-ORG_NAME, trace_name = "agent-chat" (simple), metadata = {details}
|
|
101
|
+
metadata = {}
|
|
102
|
+
|
|
103
|
+
# Always set a simple, consistent trace name
|
|
104
|
+
metadata["trace_name"] = "agent-chat"
|
|
105
|
+
metadata["generation_name"] = "agent-chat"
|
|
106
|
+
|
|
107
|
+
if user_id and organization_id:
|
|
108
|
+
# Format: EMAIL-ORG_NAME (EMAIL is the user_id)
|
|
109
|
+
metadata["trace_user_id"] = f"{user_id}-{organization_id}"
|
|
110
|
+
metadata["user_id"] = f"{user_id}-{organization_id}"
|
|
111
|
+
|
|
112
|
+
if session_id:
|
|
113
|
+
# Use session_id as trace_id to group all messages in same conversation
|
|
114
|
+
metadata["trace_id"] = session_id
|
|
115
|
+
metadata["session_id"] = session_id
|
|
116
|
+
|
|
117
|
+
# Add additional details directly to metadata for Langfuse "Metadata" column
|
|
118
|
+
# Any extra fields not in the standard spec will be saved as metadata
|
|
119
|
+
if agent_id:
|
|
120
|
+
metadata["agent_id"] = agent_id
|
|
121
|
+
if agent_name:
|
|
122
|
+
metadata["agent_name"] = agent_name
|
|
123
|
+
if user_id:
|
|
124
|
+
metadata["user_email"] = user_id
|
|
125
|
+
if organization_id:
|
|
126
|
+
metadata["organization_id"] = organization_id
|
|
127
|
+
if model_id:
|
|
128
|
+
metadata["model"] = model_id
|
|
129
|
+
|
|
130
|
+
# DEBUG: Log the complete metadata being sent
|
|
131
|
+
logger.warning(
|
|
132
|
+
"🔍 DEBUG: AGNO RUNTIME - LANGFUSE METADATA",
|
|
133
|
+
metadata=metadata,
|
|
134
|
+
user_id_input=user_id,
|
|
135
|
+
organization_id_input=organization_id,
|
|
136
|
+
agent_name_input=agent_name,
|
|
137
|
+
session_id_input=session_id,
|
|
138
|
+
metadata_json=str(metadata),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Create LiteLLM model instance with metadata
|
|
142
|
+
# Use LiteLLMLangfuse for proper Langfuse integration if available
|
|
143
|
+
if LANGFUSE_SUPPORT and metadata:
|
|
144
|
+
logger.warning(
|
|
145
|
+
"🔍 DEBUG: USING LiteLLMLangfuse CLASS FOR LANGFUSE INTEGRATION",
|
|
146
|
+
metadata=metadata,
|
|
147
|
+
)
|
|
148
|
+
litellm_model = LiteLLMLangfuse(
|
|
149
|
+
id=f"openai/{model}",
|
|
150
|
+
api_base=litellm_api_base,
|
|
151
|
+
api_key=litellm_api_key,
|
|
152
|
+
metadata=metadata,
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
logger.warning(
|
|
156
|
+
"🔍 DEBUG: USING STANDARD LiteLLM CLASS (No Langfuse integration)",
|
|
157
|
+
has_metadata=bool(metadata),
|
|
158
|
+
langfuse_available=LANGFUSE_SUPPORT,
|
|
159
|
+
note="Install agno with Langfuse support for proper metadata tracking"
|
|
160
|
+
)
|
|
161
|
+
litellm_model = LiteLLM(
|
|
162
|
+
id=f"openai/{model}",
|
|
163
|
+
api_base=litellm_api_base,
|
|
164
|
+
api_key=litellm_api_key,
|
|
165
|
+
metadata=metadata if metadata else None,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
logger.warning(
|
|
169
|
+
"🔍 DEBUG: LITELLM MODEL CREATED",
|
|
170
|
+
model_class=litellm_model.__class__.__name__,
|
|
171
|
+
model_id=f"openai/{model}",
|
|
172
|
+
api_base=litellm_api_base,
|
|
173
|
+
has_metadata=bool(metadata),
|
|
174
|
+
metadata_keys=list(metadata.keys()) if metadata else [],
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Combine skills and MCP tools
|
|
178
|
+
all_tools = []
|
|
179
|
+
if skills:
|
|
180
|
+
all_tools.extend(skills)
|
|
181
|
+
if mcp_tools:
|
|
182
|
+
all_tools.extend(mcp_tools)
|
|
183
|
+
|
|
184
|
+
# Enhance system prompt with runtime-specific additions
|
|
185
|
+
# Create per-execution prompt builder to support dynamic skill context and user context
|
|
186
|
+
from control_plane_api.worker.services.skill_context_enhancement import (
|
|
187
|
+
SkillContextEnhancement,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Create prompt builder with user context and additional context
|
|
191
|
+
prompt_builder = create_default_prompt_builder(
|
|
192
|
+
user_metadata=user_metadata,
|
|
193
|
+
additional_context=additional_context,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# Add skill context enhancement if enabled and skills are configured
|
|
197
|
+
skill_context_enabled = os.getenv("ENABLE_SKILL_CONTEXT_ENHANCEMENT", "true").lower() == "true"
|
|
198
|
+
if skill_context_enabled and skill_configs:
|
|
199
|
+
skill_context_enhancement = SkillContextEnhancement(skill_configs)
|
|
200
|
+
prompt_builder.add_enhancement(skill_context_enhancement)
|
|
201
|
+
logger.info(
|
|
202
|
+
"skill_context_enhancement_enabled",
|
|
203
|
+
skill_count=len(skill_configs),
|
|
204
|
+
agent_id=agent_id,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
enhanced_system_prompt = prompt_builder.build(
|
|
208
|
+
base_prompt=system_prompt,
|
|
209
|
+
runtime_type="agno",
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Build agent configuration
|
|
213
|
+
agent = Agent(
|
|
214
|
+
name=f"Agent {agent_id}",
|
|
215
|
+
role=enhanced_system_prompt or "You are a helpful AI assistant",
|
|
216
|
+
model=litellm_model,
|
|
217
|
+
tools=all_tools if all_tools else None,
|
|
218
|
+
tool_hooks=tool_hooks if tool_hooks else None,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
return agent
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def validate_litellm_config() -> bool:
|
|
225
|
+
"""
|
|
226
|
+
Validate LiteLLM configuration is present.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
True if configuration is valid
|
|
230
|
+
|
|
231
|
+
Raises:
|
|
232
|
+
ValueError: If configuration is invalid
|
|
233
|
+
"""
|
|
234
|
+
litellm_api_key = os.getenv("LITELLM_API_KEY")
|
|
235
|
+
|
|
236
|
+
if not litellm_api_key:
|
|
237
|
+
raise ValueError(
|
|
238
|
+
"LITELLM_API_KEY environment variable not set. "
|
|
239
|
+
"This is required for Agno runtime to function."
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
logger.debug(
|
|
243
|
+
"litellm_config_validated",
|
|
244
|
+
api_base=os.getenv("LITELLM_API_BASE", "https://llm-proxy.kubiya.ai"),
|
|
245
|
+
default_model=os.environ.get("LITELLM_DEFAULT_MODEL", "kubiya/claude-sonnet-4"),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
return True
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool execution hooks for Agno runtime.
|
|
3
|
+
|
|
4
|
+
This module provides:
|
|
5
|
+
- Tool execution event hooks
|
|
6
|
+
- Real-time event publishing to Control Plane
|
|
7
|
+
- Event callback creation
|
|
8
|
+
- Tool execution tracking
|
|
9
|
+
- Policy enforcement for tool executions
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import uuid
|
|
13
|
+
import asyncio
|
|
14
|
+
import json
|
|
15
|
+
import structlog
|
|
16
|
+
from typing import Callable, Any, Optional, Dict, TYPE_CHECKING
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from control_plane_client import ControlPlaneClient
|
|
20
|
+
from control_plane_api.worker.services.tool_enforcement import ToolEnforcementService
|
|
21
|
+
|
|
22
|
+
logger = structlog.get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _parse_json_arguments(arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Parse JSON strings in tool arguments to their proper types.
|
|
28
|
+
|
|
29
|
+
Agno sometimes passes dict/list arguments as JSON strings instead of actual objects.
|
|
30
|
+
This function detects and parses those strings into proper Python types.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
arguments: Raw tool arguments from agno
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Parsed arguments with JSON strings converted to dicts/lists
|
|
37
|
+
"""
|
|
38
|
+
if not arguments:
|
|
39
|
+
return arguments
|
|
40
|
+
|
|
41
|
+
parsed = {}
|
|
42
|
+
for key, value in arguments.items():
|
|
43
|
+
# If it's a string that looks like JSON, try to parse it
|
|
44
|
+
if isinstance(value, str) and value.strip().startswith(('{', '[')):
|
|
45
|
+
try:
|
|
46
|
+
parsed[key] = json.loads(value)
|
|
47
|
+
except (json.JSONDecodeError, ValueError):
|
|
48
|
+
# Not valid JSON, keep as string
|
|
49
|
+
parsed[key] = value
|
|
50
|
+
else:
|
|
51
|
+
parsed[key] = value
|
|
52
|
+
|
|
53
|
+
return parsed
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def create_tool_hook_for_streaming(
|
|
57
|
+
control_plane: "ControlPlaneClient",
|
|
58
|
+
execution_id: str,
|
|
59
|
+
message_id: str,
|
|
60
|
+
enforcement_context: Optional[Dict[str, Any]] = None,
|
|
61
|
+
enforcement_service: Optional["ToolEnforcementService"] = None,
|
|
62
|
+
) -> Callable:
|
|
63
|
+
"""
|
|
64
|
+
Create a tool hook for streaming execution that publishes directly to Control Plane.
|
|
65
|
+
|
|
66
|
+
This hook publishes tool events immediately (not batched) for real-time visibility.
|
|
67
|
+
Used in streaming execution mode. Includes policy enforcement checks.
|
|
68
|
+
|
|
69
|
+
IMPORTANT: Parameter names MUST match Agno's expected hook signature exactly:
|
|
70
|
+
- function_name: str - The name of the tool being called
|
|
71
|
+
- function_call: Callable - The actual function to call
|
|
72
|
+
- arguments: Dict[str, Any] - Arguments to pass to the function
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
control_plane: Control Plane client for publishing events
|
|
76
|
+
execution_id: Execution ID for this run
|
|
77
|
+
message_id: Message ID for the current assistant turn (links tool to conversation)
|
|
78
|
+
enforcement_context: Optional context for policy enforcement
|
|
79
|
+
enforcement_service: Optional enforcement service for policy checks
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Tool hook function for Agno agent
|
|
83
|
+
"""
|
|
84
|
+
def tool_hook(
|
|
85
|
+
function_name: str,
|
|
86
|
+
function_call: Callable,
|
|
87
|
+
arguments: Dict[str, Any],
|
|
88
|
+
**kwargs,
|
|
89
|
+
):
|
|
90
|
+
"""
|
|
91
|
+
Hook to capture tool execution for real-time streaming.
|
|
92
|
+
|
|
93
|
+
Agno calls this hook with exact parameter names: function_name, function_call, arguments.
|
|
94
|
+
The hook MUST call function_call(**arguments) and return the result.
|
|
95
|
+
"""
|
|
96
|
+
tool_name = function_name or "unknown"
|
|
97
|
+
# Parse JSON strings in arguments to proper types (dict/list)
|
|
98
|
+
tool_args = _parse_json_arguments(arguments or {})
|
|
99
|
+
# Use UUID for tool_execution_id to avoid collisions when tools run simultaneously
|
|
100
|
+
tool_execution_id = f"{tool_name}_{uuid.uuid4().hex[:12]}"
|
|
101
|
+
|
|
102
|
+
logger.info(
|
|
103
|
+
"tool_hook_invoked",
|
|
104
|
+
tool_name=tool_name,
|
|
105
|
+
tool_execution_id=tool_execution_id,
|
|
106
|
+
execution_id=execution_id[:8],
|
|
107
|
+
has_function_call=function_call is not None and callable(function_call),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Enforcement check (non-blocking)
|
|
111
|
+
enforcement_allowed = True
|
|
112
|
+
enforcement_violation = None
|
|
113
|
+
enforcement_metadata = {}
|
|
114
|
+
|
|
115
|
+
if enforcement_service and enforcement_context:
|
|
116
|
+
try:
|
|
117
|
+
# Run enforcement check asynchronously using control_plane's thread-local loop
|
|
118
|
+
# This reuses the same event loop for all async operations in this thread,
|
|
119
|
+
# preventing resource leaks and "await wasn't used with future" errors
|
|
120
|
+
loop = control_plane._get_thread_event_loop()
|
|
121
|
+
|
|
122
|
+
enforcement_allowed, enforcement_violation, enforcement_metadata = (
|
|
123
|
+
loop.run_until_complete(
|
|
124
|
+
enforcement_service.enforce_tool_execution(
|
|
125
|
+
tool_name=tool_name,
|
|
126
|
+
tool_args=tool_args,
|
|
127
|
+
enforcement_context={
|
|
128
|
+
**enforcement_context,
|
|
129
|
+
"execution_id": execution_id,
|
|
130
|
+
"message_id": message_id,
|
|
131
|
+
"tool_execution_id": tool_execution_id,
|
|
132
|
+
},
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
except Exception as e:
|
|
137
|
+
logger.error(
|
|
138
|
+
"enforcement_check_failed",
|
|
139
|
+
tool_name=tool_name,
|
|
140
|
+
error=str(e),
|
|
141
|
+
)
|
|
142
|
+
# Fail open - allow execution
|
|
143
|
+
enforcement_metadata = {"enforcer": "error", "error": str(e)}
|
|
144
|
+
|
|
145
|
+
# Publish tool start event (blocking call - OK in thread)
|
|
146
|
+
control_plane.publish_event(
|
|
147
|
+
execution_id=execution_id,
|
|
148
|
+
event_type="tool_started",
|
|
149
|
+
data={
|
|
150
|
+
"tool_name": tool_name,
|
|
151
|
+
"tool_execution_id": tool_execution_id,
|
|
152
|
+
"tool_arguments": tool_args,
|
|
153
|
+
"message_id": message_id, # Link tool to assistant message
|
|
154
|
+
"message": f"Executing tool: {tool_name}",
|
|
155
|
+
"enforcement": enforcement_metadata, # Add enforcement metadata
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Execute tool using Agno's function_call pattern
|
|
160
|
+
# IMPORTANT: Must call function_call(**arguments) as per Agno hook contract
|
|
161
|
+
result = None
|
|
162
|
+
error = None
|
|
163
|
+
try:
|
|
164
|
+
if function_call and callable(function_call):
|
|
165
|
+
result = function_call(**tool_args) if tool_args else function_call()
|
|
166
|
+
else:
|
|
167
|
+
raise ValueError(f"function_call not callable: {function_call}")
|
|
168
|
+
status = "success"
|
|
169
|
+
|
|
170
|
+
# Inject enforcement violation into result if blocked
|
|
171
|
+
if not enforcement_allowed and enforcement_violation:
|
|
172
|
+
# Prepend violation message to result
|
|
173
|
+
violation_prefix = f"\n{'='*60}\n"
|
|
174
|
+
violation_prefix += "⛔ POLICY VIOLATION DETECTED\n"
|
|
175
|
+
violation_prefix += f"{'='*60}\n"
|
|
176
|
+
violation_prefix += enforcement_violation
|
|
177
|
+
violation_prefix += f"\n{'='*60}\n\n"
|
|
178
|
+
|
|
179
|
+
if result:
|
|
180
|
+
result = violation_prefix + str(result)
|
|
181
|
+
else:
|
|
182
|
+
result = violation_prefix + "(Tool execution completed but blocked by policy)"
|
|
183
|
+
|
|
184
|
+
logger.warning(
|
|
185
|
+
"tool_execution_policy_violation",
|
|
186
|
+
tool_name=tool_name,
|
|
187
|
+
tool_execution_id=tool_execution_id,
|
|
188
|
+
enforcement_metadata=enforcement_metadata,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
except Exception as e:
|
|
192
|
+
error = e
|
|
193
|
+
status = "failed"
|
|
194
|
+
logger.error(
|
|
195
|
+
"tool_execution_failed",
|
|
196
|
+
tool_name=tool_name,
|
|
197
|
+
error=str(e),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Publish tool completion event with enforcement metadata
|
|
201
|
+
control_plane.publish_event(
|
|
202
|
+
execution_id=execution_id,
|
|
203
|
+
event_type="tool_completed",
|
|
204
|
+
data={
|
|
205
|
+
"tool_name": tool_name,
|
|
206
|
+
"tool_execution_id": tool_execution_id,
|
|
207
|
+
"status": status,
|
|
208
|
+
"tool_output": str(result)[:1000] if result else None,
|
|
209
|
+
"tool_error": str(error) if error else None,
|
|
210
|
+
"message_id": message_id, # Link tool to assistant message
|
|
211
|
+
"message": f"Tool {status}: {tool_name}",
|
|
212
|
+
"enforcement": enforcement_metadata, # Add enforcement metadata
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
if error:
|
|
217
|
+
raise error
|
|
218
|
+
return result
|
|
219
|
+
|
|
220
|
+
return tool_hook
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def create_tool_hook_with_callback(
|
|
224
|
+
execution_id: str,
|
|
225
|
+
message_id: str,
|
|
226
|
+
event_callback: Callable[[Dict[str, Any]], None],
|
|
227
|
+
enforcement_context: Optional[Dict[str, Any]] = None,
|
|
228
|
+
enforcement_service: Optional["ToolEnforcementService"] = None,
|
|
229
|
+
) -> Callable:
|
|
230
|
+
"""
|
|
231
|
+
Create a tool hook that uses a callback for event publishing.
|
|
232
|
+
|
|
233
|
+
This hook uses a callback function to publish events, allowing for flexible
|
|
234
|
+
event handling (batching, filtering, etc.). Used in non-streaming execution.
|
|
235
|
+
Includes policy enforcement checks.
|
|
236
|
+
|
|
237
|
+
IMPORTANT: Parameter names MUST match Agno's expected hook signature exactly:
|
|
238
|
+
- function_name: str - The name of the tool being called
|
|
239
|
+
- function_call: Callable - The actual function to call
|
|
240
|
+
- arguments: Dict[str, Any] - Arguments to pass to the function
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
execution_id: Execution ID for this run
|
|
244
|
+
message_id: Message ID for the current assistant turn
|
|
245
|
+
event_callback: Callback function for event publishing
|
|
246
|
+
enforcement_context: Optional context for policy enforcement
|
|
247
|
+
enforcement_service: Optional enforcement service for policy checks
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
Tool hook function for Agno agent
|
|
251
|
+
"""
|
|
252
|
+
def tool_hook(
|
|
253
|
+
function_name: str,
|
|
254
|
+
function_call: Callable,
|
|
255
|
+
arguments: Dict[str, Any],
|
|
256
|
+
**kwargs,
|
|
257
|
+
):
|
|
258
|
+
"""
|
|
259
|
+
Hook to capture tool execution for callback-based publishing.
|
|
260
|
+
|
|
261
|
+
Agno calls this hook with exact parameter names: function_name, function_call, arguments.
|
|
262
|
+
The hook MUST call function_call(**arguments) and return the result.
|
|
263
|
+
"""
|
|
264
|
+
tool_name = function_name or "unknown"
|
|
265
|
+
# Parse JSON strings in arguments to proper types (dict/list)
|
|
266
|
+
tool_args = _parse_json_arguments(arguments or {})
|
|
267
|
+
# Use UUID for tool_execution_id to avoid collisions
|
|
268
|
+
tool_execution_id = f"{tool_name}_{uuid.uuid4().hex[:12]}"
|
|
269
|
+
|
|
270
|
+
# Enforcement check (non-blocking)
|
|
271
|
+
enforcement_allowed = True
|
|
272
|
+
enforcement_violation = None
|
|
273
|
+
enforcement_metadata = {}
|
|
274
|
+
|
|
275
|
+
if enforcement_service and enforcement_context:
|
|
276
|
+
try:
|
|
277
|
+
# Run enforcement check asynchronously
|
|
278
|
+
# For callback-based hooks (used in non-streaming/testing), create a temporary loop
|
|
279
|
+
try:
|
|
280
|
+
loop = asyncio.get_event_loop()
|
|
281
|
+
if loop.is_closed():
|
|
282
|
+
raise RuntimeError("Event loop is closed")
|
|
283
|
+
except RuntimeError:
|
|
284
|
+
loop = asyncio.new_event_loop()
|
|
285
|
+
asyncio.set_event_loop(loop)
|
|
286
|
+
|
|
287
|
+
enforcement_allowed, enforcement_violation, enforcement_metadata = (
|
|
288
|
+
loop.run_until_complete(
|
|
289
|
+
enforcement_service.enforce_tool_execution(
|
|
290
|
+
tool_name=tool_name,
|
|
291
|
+
tool_args=tool_args,
|
|
292
|
+
enforcement_context={
|
|
293
|
+
**enforcement_context,
|
|
294
|
+
"execution_id": execution_id,
|
|
295
|
+
"message_id": message_id,
|
|
296
|
+
"tool_execution_id": tool_execution_id,
|
|
297
|
+
},
|
|
298
|
+
)
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
except Exception as e:
|
|
302
|
+
logger.error(
|
|
303
|
+
"enforcement_check_failed",
|
|
304
|
+
tool_name=tool_name,
|
|
305
|
+
error=str(e),
|
|
306
|
+
)
|
|
307
|
+
# Fail open - allow execution
|
|
308
|
+
enforcement_metadata = {"enforcer": "error", "error": str(e)}
|
|
309
|
+
|
|
310
|
+
# Publish tool start event via callback
|
|
311
|
+
event_callback(
|
|
312
|
+
{
|
|
313
|
+
"type": "tool_start",
|
|
314
|
+
"tool_name": tool_name,
|
|
315
|
+
"tool_execution_id": tool_execution_id,
|
|
316
|
+
"tool_args": tool_args,
|
|
317
|
+
"message_id": message_id,
|
|
318
|
+
"execution_id": execution_id,
|
|
319
|
+
"enforcement": enforcement_metadata, # Add enforcement metadata
|
|
320
|
+
}
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
# Execute tool using Agno's function_call pattern
|
|
324
|
+
# IMPORTANT: Must call function_call(**arguments) as per Agno hook contract
|
|
325
|
+
result = None
|
|
326
|
+
error = None
|
|
327
|
+
try:
|
|
328
|
+
if function_call and callable(function_call):
|
|
329
|
+
result = function_call(**tool_args) if tool_args else function_call()
|
|
330
|
+
else:
|
|
331
|
+
raise ValueError(f"function_call not callable: {function_call}")
|
|
332
|
+
|
|
333
|
+
status = "success"
|
|
334
|
+
|
|
335
|
+
# Inject enforcement violation into result if blocked
|
|
336
|
+
if not enforcement_allowed and enforcement_violation:
|
|
337
|
+
# Prepend violation message to result
|
|
338
|
+
violation_prefix = f"\n{'='*60}\n"
|
|
339
|
+
violation_prefix += "⛔ POLICY VIOLATION DETECTED\n"
|
|
340
|
+
violation_prefix += f"{'='*60}\n"
|
|
341
|
+
violation_prefix += enforcement_violation
|
|
342
|
+
violation_prefix += f"\n{'='*60}\n\n"
|
|
343
|
+
|
|
344
|
+
if result:
|
|
345
|
+
result = violation_prefix + str(result)
|
|
346
|
+
else:
|
|
347
|
+
result = violation_prefix + "(Tool execution completed but blocked by policy)"
|
|
348
|
+
|
|
349
|
+
logger.warning(
|
|
350
|
+
"tool_execution_policy_violation",
|
|
351
|
+
tool_name=tool_name,
|
|
352
|
+
tool_execution_id=tool_execution_id,
|
|
353
|
+
enforcement_metadata=enforcement_metadata,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
except Exception as e:
|
|
357
|
+
error = e
|
|
358
|
+
status = "failed"
|
|
359
|
+
logger.error(
|
|
360
|
+
"tool_execution_failed",
|
|
361
|
+
tool_name=tool_name,
|
|
362
|
+
error=str(e),
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
# Publish tool completion event via callback with enforcement metadata
|
|
366
|
+
event_callback(
|
|
367
|
+
{
|
|
368
|
+
"type": "tool_complete",
|
|
369
|
+
"tool_name": tool_name,
|
|
370
|
+
"tool_execution_id": tool_execution_id,
|
|
371
|
+
"status": status,
|
|
372
|
+
"output": str(result)[:1000] if result else None,
|
|
373
|
+
"error": str(error) if error else None,
|
|
374
|
+
"message_id": message_id,
|
|
375
|
+
"execution_id": execution_id,
|
|
376
|
+
"enforcement": enforcement_metadata, # Add enforcement metadata
|
|
377
|
+
}
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
if error:
|
|
381
|
+
raise error
|
|
382
|
+
|
|
383
|
+
return result
|
|
384
|
+
|
|
385
|
+
return tool_hook
|