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,389 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task Planning Agents - Agent factory functions for workflow steps
|
|
3
|
+
|
|
4
|
+
This module contains factory functions to create Agno agents for each
|
|
5
|
+
step in the task planning workflow:
|
|
6
|
+
- Step 1: Analysis & Selection Agent (tool calling + structured output)
|
|
7
|
+
- Step 2: Plan Generation Agent (structured output only)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Optional, Dict, Any, List, TYPE_CHECKING
|
|
11
|
+
import json
|
|
12
|
+
import structlog
|
|
13
|
+
|
|
14
|
+
from agno.agent import Agent
|
|
15
|
+
from agno.models.litellm import LiteLLM
|
|
16
|
+
from agno.tools.function import Function
|
|
17
|
+
|
|
18
|
+
from control_plane_api.app.models.task_planning import (
|
|
19
|
+
TaskPlanResponse,
|
|
20
|
+
AnalysisAndSelectionOutput,
|
|
21
|
+
)
|
|
22
|
+
from .models import (
|
|
23
|
+
TaskAnalysisOutput,
|
|
24
|
+
ResourceDiscoveryOutput,
|
|
25
|
+
CostEstimationOutput,
|
|
26
|
+
FastSelectionOutput,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from control_plane_api.app.lib.planning_tools.agno_toolkit import PlanningToolkit
|
|
31
|
+
|
|
32
|
+
logger = structlog.get_logger()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# ============================================================================
|
|
36
|
+
# Tool Builders for Pre-fetched Data
|
|
37
|
+
# ============================================================================
|
|
38
|
+
|
|
39
|
+
def build_prefetch_tools(outer_context: Optional[Dict[str, Any]]) -> List[Function]:
|
|
40
|
+
"""
|
|
41
|
+
Build synthetic tools for pre-fetched data access.
|
|
42
|
+
|
|
43
|
+
These tools provide instant access to cached data without API calls.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
outer_context: Pre-fetched context with agents, teams, environments, queues
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List of Function objects for pre-fetched data access
|
|
50
|
+
"""
|
|
51
|
+
tools = []
|
|
52
|
+
|
|
53
|
+
if not outer_context:
|
|
54
|
+
return tools
|
|
55
|
+
|
|
56
|
+
if outer_context.get("agents"):
|
|
57
|
+
agents_data = outer_context["agents"]
|
|
58
|
+
|
|
59
|
+
def get_top_agents() -> str:
|
|
60
|
+
"""Get top 20 pre-fetched agents (instant, no API call).
|
|
61
|
+
Use this first before calling search tools."""
|
|
62
|
+
return json.dumps({
|
|
63
|
+
"success": True,
|
|
64
|
+
"data": {
|
|
65
|
+
"agents": agents_data,
|
|
66
|
+
"count": len(agents_data),
|
|
67
|
+
"note": "Top 20 agents. Use search_agents_by_capability() if you need more."
|
|
68
|
+
}
|
|
69
|
+
}, indent=2)
|
|
70
|
+
|
|
71
|
+
tools.append(Function.from_callable(get_top_agents))
|
|
72
|
+
|
|
73
|
+
if outer_context.get("teams"):
|
|
74
|
+
teams_data = outer_context["teams"]
|
|
75
|
+
|
|
76
|
+
def get_top_teams() -> str:
|
|
77
|
+
"""Get top 20 pre-fetched teams (instant, no API call).
|
|
78
|
+
Use this first before calling search tools."""
|
|
79
|
+
return json.dumps({
|
|
80
|
+
"success": True,
|
|
81
|
+
"data": {
|
|
82
|
+
"teams": teams_data,
|
|
83
|
+
"count": len(teams_data),
|
|
84
|
+
"note": "Top 20 teams. Use search_teams_by_capability() if you need more."
|
|
85
|
+
}
|
|
86
|
+
}, indent=2)
|
|
87
|
+
|
|
88
|
+
tools.append(Function.from_callable(get_top_teams))
|
|
89
|
+
|
|
90
|
+
if outer_context.get("environments"):
|
|
91
|
+
envs_data = outer_context["environments"]
|
|
92
|
+
|
|
93
|
+
def get_top_environments() -> str:
|
|
94
|
+
"""Get top 20 pre-fetched environments (instant, no API call)."""
|
|
95
|
+
return json.dumps({
|
|
96
|
+
"success": True,
|
|
97
|
+
"data": {
|
|
98
|
+
"environments": envs_data,
|
|
99
|
+
"count": len(envs_data),
|
|
100
|
+
"note": "Top 20 environments."
|
|
101
|
+
}
|
|
102
|
+
}, indent=2)
|
|
103
|
+
|
|
104
|
+
tools.append(Function.from_callable(get_top_environments))
|
|
105
|
+
|
|
106
|
+
if outer_context.get("worker_queues"):
|
|
107
|
+
queues_data = outer_context["worker_queues"]
|
|
108
|
+
|
|
109
|
+
def get_top_worker_queues() -> str:
|
|
110
|
+
"""Get top 20 pre-fetched worker queues (instant, no API call)."""
|
|
111
|
+
return json.dumps({
|
|
112
|
+
"success": True,
|
|
113
|
+
"data": {
|
|
114
|
+
"worker_queues": queues_data,
|
|
115
|
+
"count": len(queues_data),
|
|
116
|
+
"note": "Top 20 worker queues."
|
|
117
|
+
}
|
|
118
|
+
}, indent=2)
|
|
119
|
+
|
|
120
|
+
tools.append(Function.from_callable(get_top_worker_queues))
|
|
121
|
+
|
|
122
|
+
return tools
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def build_search_tools(planning_toolkit: Optional['PlanningToolkit']) -> List[Function]:
|
|
126
|
+
"""
|
|
127
|
+
Build search tools from planning toolkit.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
planning_toolkit: Planning toolkit with search functions
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
List of Function objects for searching
|
|
134
|
+
"""
|
|
135
|
+
tools = []
|
|
136
|
+
|
|
137
|
+
if not planning_toolkit or not hasattr(planning_toolkit, 'functions'):
|
|
138
|
+
return tools
|
|
139
|
+
|
|
140
|
+
search_tool_names = [
|
|
141
|
+
"search_agents_by_capability",
|
|
142
|
+
"search_teams_by_capability",
|
|
143
|
+
"get_agent_details",
|
|
144
|
+
"get_team_details",
|
|
145
|
+
"get_fallback_agent",
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
for tool_name in search_tool_names:
|
|
149
|
+
if tool_name in planning_toolkit.functions:
|
|
150
|
+
tools.append(planning_toolkit.functions[tool_name])
|
|
151
|
+
|
|
152
|
+
return tools
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# ============================================================================
|
|
156
|
+
# Step 1: Analysis & Selection Agent
|
|
157
|
+
# ============================================================================
|
|
158
|
+
|
|
159
|
+
def create_analysis_and_selection_agent(
|
|
160
|
+
model: LiteLLM,
|
|
161
|
+
planning_toolkit: Optional['PlanningToolkit'] = None,
|
|
162
|
+
outer_context: Optional[Dict[str, Any]] = None
|
|
163
|
+
) -> Agent:
|
|
164
|
+
"""
|
|
165
|
+
Create Step 1 agent: Task Analysis & Resource Selection.
|
|
166
|
+
|
|
167
|
+
Combines task analysis and resource selection into a single efficient agent.
|
|
168
|
+
Uses pre-fetched data for instant access + search tools for specific queries.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
model: LiteLLM model instance for the agent
|
|
172
|
+
planning_toolkit: Planning toolkit with search functions
|
|
173
|
+
outer_context: Pre-fetched context (agents, teams, environments, queues)
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Configured Agent for analysis and selection
|
|
177
|
+
"""
|
|
178
|
+
# Build tools: pre-fetched data + search tools
|
|
179
|
+
toolkit_tools = build_prefetch_tools(outer_context)
|
|
180
|
+
toolkit_tools.extend(build_search_tools(planning_toolkit))
|
|
181
|
+
|
|
182
|
+
# Extract preferred_runtime from outer_context if provided
|
|
183
|
+
preferred_runtime = outer_context.get("preferred_runtime") if outer_context else None
|
|
184
|
+
|
|
185
|
+
# Build runtime preference instruction
|
|
186
|
+
if preferred_runtime:
|
|
187
|
+
runtime_instruction = f"MANDATORY: Select agents with runtime='{preferred_runtime}' (user override)"
|
|
188
|
+
else:
|
|
189
|
+
runtime_instruction = (
|
|
190
|
+
"MANDATORY: Select agents with runtime='claude_code' OVER 'default' "
|
|
191
|
+
"when both have the capability. claude_code agents are more capable."
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return Agent(
|
|
195
|
+
name="Task Analyzer & Resource Selector",
|
|
196
|
+
role="Fast agent and environment selection",
|
|
197
|
+
model=model,
|
|
198
|
+
output_schema=AnalysisAndSelectionOutput,
|
|
199
|
+
tools=toolkit_tools,
|
|
200
|
+
instructions=[
|
|
201
|
+
"Select best agent AND environment for task. BE EXTREMELY FAST.",
|
|
202
|
+
"",
|
|
203
|
+
"MANDATORY PROCESS (must call BOTH tools):",
|
|
204
|
+
"1. FIRST: Call get_top_agents() → pick best agent match",
|
|
205
|
+
"2. SECOND: Call get_top_environments() → pick first environment from list",
|
|
206
|
+
"3. Return JSON with BOTH agent AND environment selections",
|
|
207
|
+
"",
|
|
208
|
+
f"CRITICAL RUNTIME RULE: {runtime_instruction}",
|
|
209
|
+
"If multiple agents have the needed capability, ALWAYS pick the one with runtime='claude_code'.",
|
|
210
|
+
"",
|
|
211
|
+
"CRITICAL ENVIRONMENT RULE (DO NOT SKIP):",
|
|
212
|
+
"You MUST call get_top_environments() and select the FIRST environment.",
|
|
213
|
+
"Set selected_environment_id = first environment's 'id' field",
|
|
214
|
+
"Set selected_environment_name = first environment's 'name' field",
|
|
215
|
+
"NEVER leave environment fields null if environments exist!",
|
|
216
|
+
"",
|
|
217
|
+
"UUID: Use EXACT id from tool results, never invent",
|
|
218
|
+
"FALLBACK: Use get_fallback_agent() if no agent match",
|
|
219
|
+
"",
|
|
220
|
+
"OUTPUT: Pure JSON only, start with {",
|
|
221
|
+
],
|
|
222
|
+
markdown=False,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
# ============================================================================
|
|
227
|
+
# Step 2: Plan Generation Agent
|
|
228
|
+
# ============================================================================
|
|
229
|
+
|
|
230
|
+
def create_plan_generation_agent(model: LiteLLM) -> Agent:
|
|
231
|
+
"""
|
|
232
|
+
Create Step 2 agent: Structured Plan Generation.
|
|
233
|
+
|
|
234
|
+
Generates TaskPlanResponse from Step 1 output using Agno's output_schema.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
model: LiteLLM model instance for the agent
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Configured Agent for plan generation
|
|
241
|
+
"""
|
|
242
|
+
return Agent(
|
|
243
|
+
name="Plan Generator",
|
|
244
|
+
role="Generate structured execution plan",
|
|
245
|
+
model=model,
|
|
246
|
+
output_schema=TaskPlanResponse,
|
|
247
|
+
instructions=[
|
|
248
|
+
"Generate a complete TaskPlanResponse based on Step 1 analysis.",
|
|
249
|
+
"",
|
|
250
|
+
"COPY FROM STEP 1 INPUT:",
|
|
251
|
+
"- entity_id → recommended_execution.entity_id",
|
|
252
|
+
"- entity_name → recommended_execution.entity_name",
|
|
253
|
+
"- entity_type → recommended_execution.entity_type",
|
|
254
|
+
"- runtime, model_id → recommended_execution",
|
|
255
|
+
"- selected_environment_id → recommended_execution.recommended_environment_id AND selected_environment_id",
|
|
256
|
+
"- selected_environment_name → recommended_execution.recommended_environment_name AND selected_environment_name",
|
|
257
|
+
"",
|
|
258
|
+
"CRITICAL: Copy environment fields from Step 1!",
|
|
259
|
+
"If Step 1 has selected_environment_id, you MUST set:",
|
|
260
|
+
" - recommended_execution.recommended_environment_id = <same value>",
|
|
261
|
+
" - recommended_execution.recommended_environment_name = <same value>",
|
|
262
|
+
" - selected_environment_id = <same value>",
|
|
263
|
+
" - selected_environment_name = <same value>",
|
|
264
|
+
"",
|
|
265
|
+
"IMPORTANT: team_breakdown[].tasks MUST be an empty array: tasks: []",
|
|
266
|
+
"Fill ALL required fields including: estimated_time_hours in team_breakdown, without_kubiya_resources array in realized_savings.",
|
|
267
|
+
],
|
|
268
|
+
markdown=False,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
# ============================================================================
|
|
273
|
+
# Legacy Agent Factories (for backward compatibility)
|
|
274
|
+
# ============================================================================
|
|
275
|
+
|
|
276
|
+
def create_task_analysis_agent(model: LiteLLM) -> Agent:
|
|
277
|
+
"""
|
|
278
|
+
Legacy Step 1: Task Analysis Agent (deprecated).
|
|
279
|
+
|
|
280
|
+
Use create_analysis_and_selection_agent() instead.
|
|
281
|
+
"""
|
|
282
|
+
return Agent(
|
|
283
|
+
name="Task Analyzer",
|
|
284
|
+
role="Expert at understanding task requirements and complexity",
|
|
285
|
+
model=model,
|
|
286
|
+
output_schema=TaskAnalysisOutput,
|
|
287
|
+
instructions=[
|
|
288
|
+
"You analyze task descriptions to understand what's needed.",
|
|
289
|
+
"",
|
|
290
|
+
"**Your Responsibilities:**",
|
|
291
|
+
"1. Read the task description carefully",
|
|
292
|
+
"2. Identify what capabilities/skills are required (AWS, Kubernetes, Python, etc.)",
|
|
293
|
+
"3. Determine the task type (deployment, analysis, automation, etc.)",
|
|
294
|
+
"4. Assess complexity on the Fibonacci scale (1, 2, 3, 5, 8, 13, 21)",
|
|
295
|
+
"5. Decide if this needs a single agent or multiple agents (team)",
|
|
296
|
+
"",
|
|
297
|
+
"**Complexity Guidelines:**",
|
|
298
|
+
"- 1-3 points: Simple tasks (list files, basic queries, single API calls)",
|
|
299
|
+
"- 5-8 points: Medium tasks (deployments, multi-step operations)",
|
|
300
|
+
"- 13-21 points: Complex tasks (multi-system integrations, migrations)",
|
|
301
|
+
"",
|
|
302
|
+
"**Output:**",
|
|
303
|
+
"Provide clear analysis with reasoning.",
|
|
304
|
+
],
|
|
305
|
+
markdown=False,
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def create_cost_estimation_agent(model: LiteLLM) -> Agent:
|
|
310
|
+
"""
|
|
311
|
+
Legacy Step 3: Cost Estimation Agent (deprecated).
|
|
312
|
+
|
|
313
|
+
Cost estimation is now included in Step 2 (plan generation).
|
|
314
|
+
"""
|
|
315
|
+
return Agent(
|
|
316
|
+
name="Cost Estimator",
|
|
317
|
+
role="Expert at estimating time and cost for AI agent tasks",
|
|
318
|
+
model=model,
|
|
319
|
+
output_schema=CostEstimationOutput,
|
|
320
|
+
instructions=[
|
|
321
|
+
"You calculate realistic time and cost estimates for AI agent execution.",
|
|
322
|
+
"",
|
|
323
|
+
"**Pricing Reference:**",
|
|
324
|
+
"- Claude Sonnet 4: $0.003/1K input, $0.015/1K output tokens",
|
|
325
|
+
"- Claude Haiku: $0.00025/1K input, $0.00125/1K output tokens",
|
|
326
|
+
"- GPT-4o: $0.0025/1K input, $0.01/1K output tokens",
|
|
327
|
+
"- Tool calls: $0.0001 - $0.001 per call",
|
|
328
|
+
"- Worker runtime: $0.10/hour",
|
|
329
|
+
"",
|
|
330
|
+
"**Token Estimation:**",
|
|
331
|
+
"- Simple tasks (1-3 points): 2-5K input, 1-2K output",
|
|
332
|
+
"- Medium tasks (5-8 points): 5-10K input, 2-5K output",
|
|
333
|
+
"- Complex tasks (13-21 points): 10-20K input, 5-10K output",
|
|
334
|
+
"",
|
|
335
|
+
"**Output:**",
|
|
336
|
+
"Provide detailed cost breakdown with reasoning.",
|
|
337
|
+
],
|
|
338
|
+
markdown=False,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
# ============================================================================
|
|
343
|
+
# Fast Selection Agent (--local mode)
|
|
344
|
+
# ============================================================================
|
|
345
|
+
|
|
346
|
+
def create_fast_selection_agent(
|
|
347
|
+
model: LiteLLM,
|
|
348
|
+
outer_context: Dict[str, Any]
|
|
349
|
+
) -> Agent:
|
|
350
|
+
"""
|
|
351
|
+
Create fast selection agent for --local mode.
|
|
352
|
+
|
|
353
|
+
Optimized for speed with minimal output schema and pre-fetched data only.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
model: LiteLLM model instance
|
|
357
|
+
outer_context: Pre-fetched context (required for fast mode)
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
Configured Agent for fast selection
|
|
361
|
+
"""
|
|
362
|
+
# Build only pre-fetched data tools (no API calls)
|
|
363
|
+
toolkit_tools = build_prefetch_tools(outer_context)
|
|
364
|
+
|
|
365
|
+
preferred_runtime = outer_context.get("preferred_runtime")
|
|
366
|
+
if preferred_runtime:
|
|
367
|
+
runtime_instruction = f"SELECT agents with runtime='{preferred_runtime}'"
|
|
368
|
+
else:
|
|
369
|
+
runtime_instruction = "PREFER runtime='claude_code' over 'default'"
|
|
370
|
+
|
|
371
|
+
return Agent(
|
|
372
|
+
name="Fast Selector",
|
|
373
|
+
role="Quick agent and environment selection",
|
|
374
|
+
model=model,
|
|
375
|
+
output_schema=FastSelectionOutput,
|
|
376
|
+
tools=toolkit_tools,
|
|
377
|
+
instructions=[
|
|
378
|
+
"Select best agent AND environment FAST. Use pre-fetched data only.",
|
|
379
|
+
"",
|
|
380
|
+
f"RUNTIME: {runtime_instruction}",
|
|
381
|
+
"",
|
|
382
|
+
"ENVIRONMENT: Call get_top_environments(), use first environment's id and name",
|
|
383
|
+
"Set recommended_environment_id and recommended_environment_name",
|
|
384
|
+
"",
|
|
385
|
+
"UUID: Use EXACT id from tool results, never invent",
|
|
386
|
+
"OUTPUT: Pure JSON only",
|
|
387
|
+
],
|
|
388
|
+
markdown=False,
|
|
389
|
+
)
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task Planning Cache - In-memory caching for pre-fetched resources
|
|
3
|
+
|
|
4
|
+
This module provides caching functionality to avoid repeated database calls
|
|
5
|
+
for frequently accessed resources (agents, teams, environments, queues).
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- TTL-based cache expiration (default 5 minutes)
|
|
9
|
+
- Per-organization caching
|
|
10
|
+
- Thread-safe operations
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Optional, Dict, Any
|
|
14
|
+
import time
|
|
15
|
+
import threading
|
|
16
|
+
import structlog
|
|
17
|
+
|
|
18
|
+
logger = structlog.get_logger()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ============================================================================
|
|
22
|
+
# Cache Configuration
|
|
23
|
+
# ============================================================================
|
|
24
|
+
|
|
25
|
+
DEFAULT_CACHE_TTL = 300 # 5 minutes
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ============================================================================
|
|
29
|
+
# Thread-Safe Cache Implementation
|
|
30
|
+
# ============================================================================
|
|
31
|
+
|
|
32
|
+
class PrefetchCache:
|
|
33
|
+
"""
|
|
34
|
+
Thread-safe in-memory cache for pre-fetched organization resources.
|
|
35
|
+
|
|
36
|
+
Features:
|
|
37
|
+
- TTL-based expiration
|
|
38
|
+
- Per-organization isolation
|
|
39
|
+
- Automatic cleanup of expired entries
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, ttl_seconds: int = DEFAULT_CACHE_TTL):
|
|
43
|
+
self._cache: Dict[str, Dict[str, Any]] = {}
|
|
44
|
+
self._lock = threading.RLock()
|
|
45
|
+
self._ttl = ttl_seconds
|
|
46
|
+
|
|
47
|
+
def get(self, organization_id: str) -> Optional[Dict[str, Any]]:
|
|
48
|
+
"""
|
|
49
|
+
Get cached pre-fetched data for an organization if still valid.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
organization_id: Organization identifier
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Cached data dict or None if not found/expired
|
|
56
|
+
"""
|
|
57
|
+
cache_key = f"prefetch_{organization_id}"
|
|
58
|
+
|
|
59
|
+
with self._lock:
|
|
60
|
+
cached = self._cache.get(cache_key)
|
|
61
|
+
if cached and time.time() - cached.get("timestamp", 0) < self._ttl:
|
|
62
|
+
logger.info("prefetch_cache_hit", organization_id=organization_id[:8])
|
|
63
|
+
return cached.get("data")
|
|
64
|
+
|
|
65
|
+
# Clean up expired entry if exists
|
|
66
|
+
if cached:
|
|
67
|
+
del self._cache[cache_key]
|
|
68
|
+
logger.debug("prefetch_cache_expired", organization_id=organization_id[:8])
|
|
69
|
+
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
def set(self, organization_id: str, data: Dict[str, Any]) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Cache pre-fetched data for an organization.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
organization_id: Organization identifier
|
|
78
|
+
data: Data to cache (agents, teams, environments, queues)
|
|
79
|
+
"""
|
|
80
|
+
cache_key = f"prefetch_{organization_id}"
|
|
81
|
+
|
|
82
|
+
with self._lock:
|
|
83
|
+
self._cache[cache_key] = {
|
|
84
|
+
"timestamp": time.time(),
|
|
85
|
+
"data": data
|
|
86
|
+
}
|
|
87
|
+
logger.info("prefetch_cache_set", organization_id=organization_id[:8])
|
|
88
|
+
|
|
89
|
+
def invalidate(self, organization_id: str) -> bool:
|
|
90
|
+
"""
|
|
91
|
+
Invalidate (remove) cached data for an organization.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
organization_id: Organization identifier
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
True if entry was removed, False if not found
|
|
98
|
+
"""
|
|
99
|
+
cache_key = f"prefetch_{organization_id}"
|
|
100
|
+
|
|
101
|
+
with self._lock:
|
|
102
|
+
if cache_key in self._cache:
|
|
103
|
+
del self._cache[cache_key]
|
|
104
|
+
logger.info("prefetch_cache_invalidated", organization_id=organization_id[:8])
|
|
105
|
+
return True
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
def clear(self) -> int:
|
|
109
|
+
"""
|
|
110
|
+
Clear all cached data.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Number of entries cleared
|
|
114
|
+
"""
|
|
115
|
+
with self._lock:
|
|
116
|
+
count = len(self._cache)
|
|
117
|
+
self._cache.clear()
|
|
118
|
+
logger.info("prefetch_cache_cleared", entries_cleared=count)
|
|
119
|
+
return count
|
|
120
|
+
|
|
121
|
+
def cleanup_expired(self) -> int:
|
|
122
|
+
"""
|
|
123
|
+
Remove all expired entries from cache.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Number of entries removed
|
|
127
|
+
"""
|
|
128
|
+
current_time = time.time()
|
|
129
|
+
removed = 0
|
|
130
|
+
|
|
131
|
+
with self._lock:
|
|
132
|
+
expired_keys = [
|
|
133
|
+
key for key, value in self._cache.items()
|
|
134
|
+
if current_time - value.get("timestamp", 0) >= self._ttl
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
for key in expired_keys:
|
|
138
|
+
del self._cache[key]
|
|
139
|
+
removed += 1
|
|
140
|
+
|
|
141
|
+
if removed > 0:
|
|
142
|
+
logger.info("prefetch_cache_cleanup", entries_removed=removed)
|
|
143
|
+
|
|
144
|
+
return removed
|
|
145
|
+
|
|
146
|
+
def stats(self) -> Dict[str, Any]:
|
|
147
|
+
"""
|
|
148
|
+
Get cache statistics.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Dict with cache stats (size, oldest entry age, etc.)
|
|
152
|
+
"""
|
|
153
|
+
current_time = time.time()
|
|
154
|
+
|
|
155
|
+
with self._lock:
|
|
156
|
+
if not self._cache:
|
|
157
|
+
return {"size": 0, "oldest_age_seconds": 0, "ttl_seconds": self._ttl}
|
|
158
|
+
|
|
159
|
+
ages = [
|
|
160
|
+
current_time - v.get("timestamp", current_time)
|
|
161
|
+
for v in self._cache.values()
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
"size": len(self._cache),
|
|
166
|
+
"oldest_age_seconds": max(ages) if ages else 0,
|
|
167
|
+
"newest_age_seconds": min(ages) if ages else 0,
|
|
168
|
+
"ttl_seconds": self._ttl
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# ============================================================================
|
|
173
|
+
# Global Cache Instance (Singleton)
|
|
174
|
+
# ============================================================================
|
|
175
|
+
|
|
176
|
+
_prefetch_cache: Optional[PrefetchCache] = None
|
|
177
|
+
_cache_lock = threading.Lock()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_prefetch_cache() -> PrefetchCache:
|
|
181
|
+
"""
|
|
182
|
+
Get the global prefetch cache instance (singleton).
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
PrefetchCache instance
|
|
186
|
+
"""
|
|
187
|
+
global _prefetch_cache
|
|
188
|
+
|
|
189
|
+
if _prefetch_cache is None:
|
|
190
|
+
with _cache_lock:
|
|
191
|
+
if _prefetch_cache is None:
|
|
192
|
+
_prefetch_cache = PrefetchCache()
|
|
193
|
+
|
|
194
|
+
return _prefetch_cache
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# ============================================================================
|
|
198
|
+
# Convenience Functions (backward compatible)
|
|
199
|
+
# ============================================================================
|
|
200
|
+
|
|
201
|
+
def get_cached_prefetch(organization_id: str) -> Optional[Dict[str, Any]]:
|
|
202
|
+
"""Get cached pre-fetched data for an organization if still valid."""
|
|
203
|
+
return get_prefetch_cache().get(organization_id)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def set_cached_prefetch(organization_id: str, data: Dict[str, Any]) -> None:
|
|
207
|
+
"""Cache pre-fetched data for an organization."""
|
|
208
|
+
get_prefetch_cache().set(organization_id, data)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def invalidate_prefetch_cache(organization_id: str) -> bool:
|
|
212
|
+
"""Invalidate cached data for an organization."""
|
|
213
|
+
return get_prefetch_cache().invalidate(organization_id)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def clear_prefetch_cache() -> int:
|
|
217
|
+
"""Clear all cached data."""
|
|
218
|
+
return get_prefetch_cache().clear()
|