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,834 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data Visualization Tools for Agent Control Plane Worker
|
|
3
|
+
|
|
4
|
+
This module provides tools for agents to create diagrams and visualizations
|
|
5
|
+
using Mermaid syntax. The tools emit special events that the UI can parse
|
|
6
|
+
and render as interactive diagrams.
|
|
7
|
+
|
|
8
|
+
Event Format:
|
|
9
|
+
The tool emits events in the following format:
|
|
10
|
+
|
|
11
|
+
<<DIAGRAM_START>>
|
|
12
|
+
```mermaid
|
|
13
|
+
[mermaid diagram code]
|
|
14
|
+
```
|
|
15
|
+
<<DIAGRAM_END>>
|
|
16
|
+
|
|
17
|
+
This format allows the UI to:
|
|
18
|
+
1. Detect diagram events via <<DIAGRAM_START>> and <<DIAGRAM_END>> markers
|
|
19
|
+
2. Extract the Mermaid syntax between the markers
|
|
20
|
+
3. Render the diagram using a Mermaid renderer component
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import re
|
|
25
|
+
from typing import Optional, Callable, Any, Dict, List
|
|
26
|
+
from agno.tools import Toolkit
|
|
27
|
+
from control_plane_api.worker.skills.builtin.schema_fix_mixin import SchemaFixMixin
|
|
28
|
+
|
|
29
|
+
import structlog
|
|
30
|
+
|
|
31
|
+
logger = structlog.get_logger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Mermaid syntax validation patterns
|
|
35
|
+
MERMAID_DIAGRAM_TYPES = {
|
|
36
|
+
'flowchart': r'^flowchart\s+(TD|TB|BT|RL|LR)',
|
|
37
|
+
'graph': r'^graph\s+(TD|TB|BT|RL|LR)',
|
|
38
|
+
'sequenceDiagram': r'^sequenceDiagram',
|
|
39
|
+
'classDiagram': r'^classDiagram',
|
|
40
|
+
'stateDiagram': r'^stateDiagram(-v2)?',
|
|
41
|
+
'erDiagram': r'^erDiagram',
|
|
42
|
+
'journey': r'^journey',
|
|
43
|
+
'gantt': r'^gantt',
|
|
44
|
+
'pie': r'^pie',
|
|
45
|
+
'gitGraph': r'^gitGraph',
|
|
46
|
+
'mindmap': r'^mindmap',
|
|
47
|
+
'timeline': r'^timeline',
|
|
48
|
+
'quadrantChart': r'^quadrantChart',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Forbidden patterns that could cause rendering issues
|
|
52
|
+
FORBIDDEN_PATTERNS = [
|
|
53
|
+
r'<script', # No script tags
|
|
54
|
+
r'javascript:', # No javascript: URLs
|
|
55
|
+
r'on\w+\s*=', # No event handlers
|
|
56
|
+
r'eval\(', # No eval
|
|
57
|
+
r'\.innerHTML', # No innerHTML manipulation
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class MermaidValidator:
|
|
62
|
+
"""Validates Mermaid diagram syntax to ensure safe and correct rendering."""
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def validate_syntax(diagram_code: str, expected_type: Optional[str] = None) -> tuple[bool, Optional[str]]:
|
|
66
|
+
"""
|
|
67
|
+
Validate Mermaid diagram syntax.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
diagram_code: The Mermaid diagram code to validate
|
|
71
|
+
expected_type: Optional expected diagram type (e.g., 'flowchart', 'sequenceDiagram')
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Tuple of (is_valid, error_message)
|
|
75
|
+
"""
|
|
76
|
+
if not diagram_code or not diagram_code.strip():
|
|
77
|
+
return False, "Diagram code is empty"
|
|
78
|
+
|
|
79
|
+
# Check for forbidden patterns
|
|
80
|
+
for pattern in FORBIDDEN_PATTERNS:
|
|
81
|
+
if re.search(pattern, diagram_code, re.IGNORECASE):
|
|
82
|
+
return False, f"Forbidden pattern detected: {pattern}"
|
|
83
|
+
|
|
84
|
+
# Check for valid diagram type
|
|
85
|
+
diagram_lines = [line.strip() for line in diagram_code.strip().split('\n') if line.strip()]
|
|
86
|
+
if not diagram_lines:
|
|
87
|
+
return False, "No content in diagram"
|
|
88
|
+
|
|
89
|
+
# Skip metadata lines (---...---)
|
|
90
|
+
first_code_line = None
|
|
91
|
+
in_metadata = False
|
|
92
|
+
for line in diagram_lines:
|
|
93
|
+
if line == '---':
|
|
94
|
+
in_metadata = not in_metadata
|
|
95
|
+
continue
|
|
96
|
+
if not in_metadata and line:
|
|
97
|
+
first_code_line = line
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
if not first_code_line:
|
|
101
|
+
return False, "No diagram definition found"
|
|
102
|
+
|
|
103
|
+
# Validate diagram type
|
|
104
|
+
found_valid_type = False
|
|
105
|
+
detected_type = None
|
|
106
|
+
for diagram_type, pattern in MERMAID_DIAGRAM_TYPES.items():
|
|
107
|
+
if re.match(pattern, first_code_line, re.IGNORECASE):
|
|
108
|
+
found_valid_type = True
|
|
109
|
+
detected_type = diagram_type
|
|
110
|
+
break
|
|
111
|
+
|
|
112
|
+
if not found_valid_type:
|
|
113
|
+
return False, f"Invalid diagram type. First line: {first_code_line[:50]}"
|
|
114
|
+
|
|
115
|
+
# If expected type provided, verify it matches
|
|
116
|
+
if expected_type and detected_type:
|
|
117
|
+
if expected_type.lower() not in detected_type.lower():
|
|
118
|
+
return False, f"Expected {expected_type} but detected {detected_type}"
|
|
119
|
+
|
|
120
|
+
# Check for balanced brackets/parentheses (basic structural validation)
|
|
121
|
+
open_chars = {'(': 0, '[': 0, '{': 0}
|
|
122
|
+
close_chars = {')': '(', ']': '[', '}': '{'}
|
|
123
|
+
stack = []
|
|
124
|
+
|
|
125
|
+
for char in diagram_code:
|
|
126
|
+
if char in open_chars:
|
|
127
|
+
stack.append(char)
|
|
128
|
+
elif char in close_chars:
|
|
129
|
+
if not stack or stack[-1] != close_chars[char]:
|
|
130
|
+
# Don't fail on unbalanced - just warn
|
|
131
|
+
logger.warning(f"Potentially unbalanced brackets in diagram")
|
|
132
|
+
elif stack:
|
|
133
|
+
stack.pop()
|
|
134
|
+
|
|
135
|
+
return True, None
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def sanitize_content(content: str) -> str:
|
|
139
|
+
"""
|
|
140
|
+
Sanitize diagram content to remove potentially problematic characters.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
content: Content to sanitize
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Sanitized content
|
|
147
|
+
"""
|
|
148
|
+
# Remove null bytes
|
|
149
|
+
content = content.replace('\x00', '')
|
|
150
|
+
|
|
151
|
+
# Normalize line endings
|
|
152
|
+
content = content.replace('\r\n', '\n').replace('\r', '\n')
|
|
153
|
+
|
|
154
|
+
# Remove excessive whitespace while preserving structure
|
|
155
|
+
lines = content.split('\n')
|
|
156
|
+
cleaned_lines = []
|
|
157
|
+
for line in lines:
|
|
158
|
+
# Preserve indentation but trim trailing spaces
|
|
159
|
+
cleaned_line = line.rstrip()
|
|
160
|
+
cleaned_lines.append(cleaned_line)
|
|
161
|
+
|
|
162
|
+
return '\n'.join(cleaned_lines)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class DataVisualizationTools(SchemaFixMixin, Toolkit):
|
|
166
|
+
"""
|
|
167
|
+
Data Visualization toolkit for creating diagrams using Mermaid syntax.
|
|
168
|
+
|
|
169
|
+
Agents can use these tools to create various types of diagrams for:
|
|
170
|
+
- Data analysis and BI intelligence
|
|
171
|
+
- System architecture visualization
|
|
172
|
+
- Process flows and workflows
|
|
173
|
+
- Database schemas and ER diagrams
|
|
174
|
+
- Project timelines and Gantt charts
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def __init__(
|
|
178
|
+
self,
|
|
179
|
+
max_diagram_size: int = 50000,
|
|
180
|
+
enable_flowchart: bool = True,
|
|
181
|
+
enable_sequence: bool = True,
|
|
182
|
+
enable_class_diagram: bool = True,
|
|
183
|
+
enable_er_diagram: bool = True,
|
|
184
|
+
enable_gantt: bool = True,
|
|
185
|
+
enable_pie_chart: bool = True,
|
|
186
|
+
enable_state_diagram: bool = True,
|
|
187
|
+
enable_git_graph: bool = True,
|
|
188
|
+
enable_user_journey: bool = True,
|
|
189
|
+
enable_quadrant_chart: bool = True,
|
|
190
|
+
stream_callback: Optional[Callable[[str], None]] = None,
|
|
191
|
+
**kwargs # Accept additional parameters like execution_id
|
|
192
|
+
):
|
|
193
|
+
"""
|
|
194
|
+
Initialize DataVisualizationTools.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
max_diagram_size: Maximum size of diagram in characters
|
|
198
|
+
enable_*: Enable/disable specific diagram types
|
|
199
|
+
**kwargs: Additional configuration (e.g., execution_id)
|
|
200
|
+
stream_callback: Optional callback for streaming output
|
|
201
|
+
"""
|
|
202
|
+
super().__init__(name="data_visualization")
|
|
203
|
+
|
|
204
|
+
self.max_diagram_size = max_diagram_size
|
|
205
|
+
self.enable_flowchart = enable_flowchart
|
|
206
|
+
self.enable_sequence = enable_sequence
|
|
207
|
+
self.enable_class_diagram = enable_class_diagram
|
|
208
|
+
self.enable_er_diagram = enable_er_diagram
|
|
209
|
+
self.enable_gantt = enable_gantt
|
|
210
|
+
self.enable_pie_chart = enable_pie_chart
|
|
211
|
+
self.enable_state_diagram = enable_state_diagram
|
|
212
|
+
self.enable_git_graph = enable_git_graph
|
|
213
|
+
self.enable_user_journey = enable_user_journey
|
|
214
|
+
self.enable_quadrant_chart = enable_quadrant_chart
|
|
215
|
+
self.stream_callback = stream_callback
|
|
216
|
+
|
|
217
|
+
# Register all enabled tools
|
|
218
|
+
if enable_flowchart:
|
|
219
|
+
self.register(self.create_flowchart)
|
|
220
|
+
if enable_sequence:
|
|
221
|
+
self.register(self.create_sequence_diagram)
|
|
222
|
+
if enable_class_diagram:
|
|
223
|
+
self.register(self.create_class_diagram)
|
|
224
|
+
if enable_er_diagram:
|
|
225
|
+
self.register(self.create_er_diagram)
|
|
226
|
+
if enable_gantt:
|
|
227
|
+
self.register(self.create_gantt_chart)
|
|
228
|
+
if enable_pie_chart:
|
|
229
|
+
self.register(self.create_pie_chart)
|
|
230
|
+
if enable_state_diagram:
|
|
231
|
+
self.register(self.create_state_diagram)
|
|
232
|
+
if enable_git_graph:
|
|
233
|
+
self.register(self.create_git_graph)
|
|
234
|
+
if enable_user_journey:
|
|
235
|
+
self.register(self.create_user_journey)
|
|
236
|
+
if enable_quadrant_chart:
|
|
237
|
+
self.register(self.create_quadrant_chart)
|
|
238
|
+
|
|
239
|
+
# Generic create_diagram tool
|
|
240
|
+
self.register(self.create_diagram)
|
|
241
|
+
|
|
242
|
+
# Fix: Rebuild function schemas with proper parameters
|
|
243
|
+
self._rebuild_function_schemas()
|
|
244
|
+
|
|
245
|
+
def _emit_diagram(
|
|
246
|
+
self,
|
|
247
|
+
diagram_code: str,
|
|
248
|
+
diagram_type: str,
|
|
249
|
+
validate: bool = True,
|
|
250
|
+
auto_fix: bool = True
|
|
251
|
+
) -> str:
|
|
252
|
+
"""
|
|
253
|
+
Emit a diagram event with proper formatting for UI parsing.
|
|
254
|
+
Includes validation, sanitization, and error handling.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
diagram_code: Mermaid diagram code
|
|
258
|
+
diagram_type: Type of diagram (for logging/metadata)
|
|
259
|
+
validate: Whether to validate the diagram syntax (default: True)
|
|
260
|
+
auto_fix: Whether to attempt auto-fixing common issues (default: True)
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Formatted diagram event string or error message
|
|
264
|
+
"""
|
|
265
|
+
try:
|
|
266
|
+
# Sanitize content
|
|
267
|
+
sanitized_code = MermaidValidator.sanitize_content(diagram_code)
|
|
268
|
+
|
|
269
|
+
# Validate size
|
|
270
|
+
if len(sanitized_code) > self.max_diagram_size:
|
|
271
|
+
error_msg = f"Error: Diagram exceeds maximum size of {self.max_diagram_size} characters (current: {len(sanitized_code)})"
|
|
272
|
+
logger.error(f"[DataVisualization] {error_msg}")
|
|
273
|
+
return error_msg
|
|
274
|
+
|
|
275
|
+
# Validate syntax if enabled
|
|
276
|
+
if validate:
|
|
277
|
+
is_valid, error_message = MermaidValidator.validate_syntax(
|
|
278
|
+
sanitized_code,
|
|
279
|
+
expected_type=diagram_type
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
if not is_valid:
|
|
283
|
+
if auto_fix:
|
|
284
|
+
# Attempt to fix common issues
|
|
285
|
+
fixed_code = self._attempt_fix(sanitized_code, diagram_type)
|
|
286
|
+
if fixed_code:
|
|
287
|
+
# Re-validate fixed code
|
|
288
|
+
is_valid, error_message = MermaidValidator.validate_syntax(
|
|
289
|
+
fixed_code,
|
|
290
|
+
expected_type=diagram_type
|
|
291
|
+
)
|
|
292
|
+
if is_valid:
|
|
293
|
+
logger.info(f"[DataVisualization] Auto-fixed diagram syntax issue")
|
|
294
|
+
sanitized_code = fixed_code
|
|
295
|
+
else:
|
|
296
|
+
error_msg = f"Error: Invalid diagram syntax - {error_message}\n\nAttempted auto-fix failed. Please check your Mermaid syntax."
|
|
297
|
+
logger.error(f"[DataVisualization] {error_msg}")
|
|
298
|
+
return error_msg
|
|
299
|
+
else:
|
|
300
|
+
error_msg = f"Error: Invalid diagram syntax - {error_message}"
|
|
301
|
+
logger.error(f"[DataVisualization] {error_msg}")
|
|
302
|
+
return error_msg
|
|
303
|
+
|
|
304
|
+
# Log successful validation
|
|
305
|
+
logger.info(
|
|
306
|
+
f"[DataVisualization] Emitting {diagram_type} diagram "
|
|
307
|
+
f"({len(sanitized_code)} chars)"
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# Format the diagram event
|
|
311
|
+
output = f"""<<DIAGRAM_START>>
|
|
312
|
+
```mermaid
|
|
313
|
+
{sanitized_code.strip()}
|
|
314
|
+
```
|
|
315
|
+
<<DIAGRAM_END>>"""
|
|
316
|
+
|
|
317
|
+
# Stream if callback provided
|
|
318
|
+
if self.stream_callback:
|
|
319
|
+
try:
|
|
320
|
+
self.stream_callback(output)
|
|
321
|
+
except Exception as stream_error:
|
|
322
|
+
logger.error(
|
|
323
|
+
f"[DataVisualization] Stream callback failed: {stream_error}"
|
|
324
|
+
)
|
|
325
|
+
# Continue anyway - the output is still returned
|
|
326
|
+
|
|
327
|
+
return output
|
|
328
|
+
|
|
329
|
+
except Exception as e:
|
|
330
|
+
error_msg = f"Error: Failed to emit diagram - {str(e)}"
|
|
331
|
+
logger.error(f"[DataVisualization] {error_msg}", exc_info=True)
|
|
332
|
+
return error_msg
|
|
333
|
+
|
|
334
|
+
def _attempt_fix(self, diagram_code: str, diagram_type: str) -> Optional[str]:
|
|
335
|
+
"""
|
|
336
|
+
Attempt to auto-fix common diagram syntax issues.
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
diagram_code: The diagram code with issues
|
|
340
|
+
diagram_type: The type of diagram
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
Fixed diagram code or None if can't be fixed
|
|
344
|
+
"""
|
|
345
|
+
try:
|
|
346
|
+
lines = diagram_code.split('\n')
|
|
347
|
+
fixed_lines = []
|
|
348
|
+
|
|
349
|
+
for line in lines:
|
|
350
|
+
# Remove trailing semicolons (common mistake)
|
|
351
|
+
if line.rstrip().endswith(';'):
|
|
352
|
+
line = line.rstrip()[:-1]
|
|
353
|
+
|
|
354
|
+
# Fix common arrow syntax issues
|
|
355
|
+
line = line.replace('-->', '-->').replace('--->', '-->')
|
|
356
|
+
|
|
357
|
+
fixed_lines.append(line)
|
|
358
|
+
|
|
359
|
+
return '\n'.join(fixed_lines)
|
|
360
|
+
except Exception as e:
|
|
361
|
+
logger.warning(f"[DataVisualization] Auto-fix failed: {e}")
|
|
362
|
+
return None
|
|
363
|
+
|
|
364
|
+
def create_diagram(
|
|
365
|
+
self, diagram_code: str, diagram_type: str = "flowchart"
|
|
366
|
+
) -> str:
|
|
367
|
+
"""
|
|
368
|
+
Create a diagram from Mermaid syntax.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
diagram_code: Complete Mermaid diagram code
|
|
372
|
+
diagram_type: Type of diagram (for metadata)
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
Success message with diagram event
|
|
376
|
+
|
|
377
|
+
Example:
|
|
378
|
+
create_diagram('''
|
|
379
|
+
flowchart TD
|
|
380
|
+
A[Start] --> B{Decision}
|
|
381
|
+
B -->|Yes| C[Action 1]
|
|
382
|
+
B -->|No| D[Action 2]
|
|
383
|
+
''', 'flowchart')
|
|
384
|
+
"""
|
|
385
|
+
return self._emit_diagram(diagram_code, diagram_type)
|
|
386
|
+
|
|
387
|
+
def create_flowchart(
|
|
388
|
+
self,
|
|
389
|
+
title: str,
|
|
390
|
+
nodes: str,
|
|
391
|
+
direction: str = "TD",
|
|
392
|
+
) -> str:
|
|
393
|
+
"""
|
|
394
|
+
Create a flowchart diagram with automatic validation and error recovery.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
title: Title of the flowchart
|
|
398
|
+
nodes: Mermaid flowchart node definitions
|
|
399
|
+
direction: Direction (TD=top-down, LR=left-right, RL=right-left, BT=bottom-top)
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Success message with diagram event or error message
|
|
403
|
+
|
|
404
|
+
Example:
|
|
405
|
+
create_flowchart(
|
|
406
|
+
title="User Login Flow",
|
|
407
|
+
nodes='''
|
|
408
|
+
A[User] --> B[Login Page]
|
|
409
|
+
B --> C{Valid?}
|
|
410
|
+
C -->|Yes| D[Dashboard]
|
|
411
|
+
C -->|No| E[Error]
|
|
412
|
+
''',
|
|
413
|
+
direction="TD"
|
|
414
|
+
)
|
|
415
|
+
"""
|
|
416
|
+
try:
|
|
417
|
+
# Validate direction parameter
|
|
418
|
+
valid_directions = ['TD', 'TB', 'BT', 'RL', 'LR']
|
|
419
|
+
direction = direction.upper()
|
|
420
|
+
if direction not in valid_directions:
|
|
421
|
+
logger.warning(
|
|
422
|
+
f"[DataVisualization] Invalid direction '{direction}', "
|
|
423
|
+
f"defaulting to 'TD'. Valid: {valid_directions}"
|
|
424
|
+
)
|
|
425
|
+
direction = 'TD'
|
|
426
|
+
|
|
427
|
+
# Sanitize title
|
|
428
|
+
title = title.replace('"', "'").strip()
|
|
429
|
+
if not title:
|
|
430
|
+
title = "Flowchart"
|
|
431
|
+
|
|
432
|
+
# Build diagram
|
|
433
|
+
diagram = f"""---
|
|
434
|
+
title: {title}
|
|
435
|
+
---
|
|
436
|
+
flowchart {direction}
|
|
437
|
+
{nodes.strip()}"""
|
|
438
|
+
|
|
439
|
+
return self._emit_diagram(diagram, "flowchart")
|
|
440
|
+
|
|
441
|
+
except Exception as e:
|
|
442
|
+
error_msg = f"Error creating flowchart: {str(e)}"
|
|
443
|
+
logger.error(f"[DataVisualization] {error_msg}", exc_info=True)
|
|
444
|
+
return error_msg
|
|
445
|
+
|
|
446
|
+
def create_sequence_diagram(
|
|
447
|
+
self,
|
|
448
|
+
title: str,
|
|
449
|
+
participants: list[str],
|
|
450
|
+
interactions: str,
|
|
451
|
+
) -> str:
|
|
452
|
+
"""
|
|
453
|
+
Create a sequence diagram.
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
title: Title of the sequence diagram
|
|
457
|
+
participants: List of participant names
|
|
458
|
+
interactions: Mermaid sequence diagram interactions
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
Success message with diagram event
|
|
462
|
+
|
|
463
|
+
Example:
|
|
464
|
+
create_sequence_diagram(
|
|
465
|
+
title="API Authentication Flow",
|
|
466
|
+
participants=["Client", "API", "Database"],
|
|
467
|
+
interactions='''
|
|
468
|
+
Client->>API: POST /login
|
|
469
|
+
API->>Database: Verify credentials
|
|
470
|
+
Database-->>API: User data
|
|
471
|
+
API-->>Client: JWT token
|
|
472
|
+
'''
|
|
473
|
+
)
|
|
474
|
+
"""
|
|
475
|
+
participant_defs = "\n".join([f" participant {p}" for p in participants])
|
|
476
|
+
diagram = f"""---
|
|
477
|
+
title: {title}
|
|
478
|
+
---
|
|
479
|
+
sequenceDiagram
|
|
480
|
+
{participant_defs}
|
|
481
|
+
{interactions.strip()}"""
|
|
482
|
+
return self._emit_diagram(diagram, "sequence")
|
|
483
|
+
|
|
484
|
+
def create_class_diagram(
|
|
485
|
+
self,
|
|
486
|
+
title: str,
|
|
487
|
+
classes: str,
|
|
488
|
+
) -> str:
|
|
489
|
+
"""
|
|
490
|
+
Create a class diagram.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
title: Title of the class diagram
|
|
494
|
+
classes: Mermaid class diagram definitions
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
Success message with diagram event
|
|
498
|
+
|
|
499
|
+
Example:
|
|
500
|
+
create_class_diagram(
|
|
501
|
+
title="User Management System",
|
|
502
|
+
classes='''
|
|
503
|
+
class User {
|
|
504
|
+
+String name
|
|
505
|
+
+String email
|
|
506
|
+
+login()
|
|
507
|
+
+logout()
|
|
508
|
+
}
|
|
509
|
+
class Admin {
|
|
510
|
+
+String permissions
|
|
511
|
+
+deleteUser()
|
|
512
|
+
}
|
|
513
|
+
User <|-- Admin
|
|
514
|
+
'''
|
|
515
|
+
)
|
|
516
|
+
"""
|
|
517
|
+
diagram = f"""---
|
|
518
|
+
title: {title}
|
|
519
|
+
---
|
|
520
|
+
classDiagram
|
|
521
|
+
{classes.strip()}"""
|
|
522
|
+
return self._emit_diagram(diagram, "class")
|
|
523
|
+
|
|
524
|
+
def create_er_diagram(
|
|
525
|
+
self,
|
|
526
|
+
title: str,
|
|
527
|
+
entities: str,
|
|
528
|
+
) -> str:
|
|
529
|
+
"""
|
|
530
|
+
Create an Entity-Relationship diagram.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
title: Title of the ER diagram
|
|
534
|
+
entities: Mermaid ER diagram definitions
|
|
535
|
+
|
|
536
|
+
Returns:
|
|
537
|
+
Success message with diagram event
|
|
538
|
+
|
|
539
|
+
Example:
|
|
540
|
+
create_er_diagram(
|
|
541
|
+
title="E-commerce Database Schema",
|
|
542
|
+
entities='''
|
|
543
|
+
CUSTOMER ||--o{ ORDER : places
|
|
544
|
+
ORDER ||--|{ LINE-ITEM : contains
|
|
545
|
+
PRODUCT ||--o{ LINE-ITEM : includes
|
|
546
|
+
'''
|
|
547
|
+
)
|
|
548
|
+
"""
|
|
549
|
+
diagram = f"""---
|
|
550
|
+
title: {title}
|
|
551
|
+
---
|
|
552
|
+
erDiagram
|
|
553
|
+
{entities.strip()}"""
|
|
554
|
+
return self._emit_diagram(diagram, "er")
|
|
555
|
+
|
|
556
|
+
def create_gantt_chart(
|
|
557
|
+
self,
|
|
558
|
+
title: str,
|
|
559
|
+
tasks: str,
|
|
560
|
+
date_format: str = "YYYY-MM-DD",
|
|
561
|
+
) -> str:
|
|
562
|
+
"""
|
|
563
|
+
Create a Gantt chart.
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
title: Title of the Gantt chart
|
|
567
|
+
tasks: Mermaid Gantt chart task definitions
|
|
568
|
+
date_format: Date format (default: YYYY-MM-DD)
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
Success message with diagram event
|
|
572
|
+
|
|
573
|
+
Example:
|
|
574
|
+
create_gantt_chart(
|
|
575
|
+
title="Project Timeline",
|
|
576
|
+
tasks='''
|
|
577
|
+
section Planning
|
|
578
|
+
Requirements : 2024-01-01, 2w
|
|
579
|
+
Design : 2024-01-15, 1w
|
|
580
|
+
section Development
|
|
581
|
+
Backend : 2024-01-22, 3w
|
|
582
|
+
Frontend : 2024-02-05, 3w
|
|
583
|
+
'''
|
|
584
|
+
)
|
|
585
|
+
"""
|
|
586
|
+
diagram = f"""---
|
|
587
|
+
title: {title}
|
|
588
|
+
---
|
|
589
|
+
gantt
|
|
590
|
+
dateFormat {date_format}
|
|
591
|
+
{tasks.strip()}"""
|
|
592
|
+
return self._emit_diagram(diagram, "gantt")
|
|
593
|
+
|
|
594
|
+
def create_pie_chart(
|
|
595
|
+
self,
|
|
596
|
+
title: str,
|
|
597
|
+
data: dict[str, float],
|
|
598
|
+
) -> str:
|
|
599
|
+
"""
|
|
600
|
+
Create a pie chart with data validation.
|
|
601
|
+
|
|
602
|
+
Args:
|
|
603
|
+
title: Title of the pie chart
|
|
604
|
+
data: Dictionary of label: value pairs
|
|
605
|
+
|
|
606
|
+
Returns:
|
|
607
|
+
Success message with diagram event or error message
|
|
608
|
+
|
|
609
|
+
Example:
|
|
610
|
+
create_pie_chart(
|
|
611
|
+
title="Revenue by Product",
|
|
612
|
+
data={
|
|
613
|
+
"Product A": 35.5,
|
|
614
|
+
"Product B": 28.3,
|
|
615
|
+
"Product C": 20.1,
|
|
616
|
+
"Product D": 16.1
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
"""
|
|
620
|
+
try:
|
|
621
|
+
# Validate data
|
|
622
|
+
if not data or not isinstance(data, dict):
|
|
623
|
+
return "Error: Pie chart data must be a non-empty dictionary"
|
|
624
|
+
|
|
625
|
+
if len(data) == 0:
|
|
626
|
+
return "Error: Pie chart must have at least one data point"
|
|
627
|
+
|
|
628
|
+
if len(data) > 50:
|
|
629
|
+
logger.warning(
|
|
630
|
+
f"[DataVisualization] Pie chart has {len(data)} slices, "
|
|
631
|
+
"which may be hard to read. Consider grouping data."
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
# Validate and sanitize data
|
|
635
|
+
validated_data = {}
|
|
636
|
+
for label, value in data.items():
|
|
637
|
+
# Sanitize label
|
|
638
|
+
clean_label = str(label).replace('"', "'").strip()
|
|
639
|
+
if not clean_label:
|
|
640
|
+
clean_label = "Unnamed"
|
|
641
|
+
|
|
642
|
+
# Validate value
|
|
643
|
+
try:
|
|
644
|
+
numeric_value = float(value)
|
|
645
|
+
if numeric_value < 0:
|
|
646
|
+
logger.warning(
|
|
647
|
+
f"[DataVisualization] Negative value for '{clean_label}': {numeric_value}, "
|
|
648
|
+
"using absolute value"
|
|
649
|
+
)
|
|
650
|
+
numeric_value = abs(numeric_value)
|
|
651
|
+
validated_data[clean_label] = numeric_value
|
|
652
|
+
except (ValueError, TypeError):
|
|
653
|
+
logger.warning(
|
|
654
|
+
f"[DataVisualization] Invalid value for '{clean_label}': {value}, skipping"
|
|
655
|
+
)
|
|
656
|
+
continue
|
|
657
|
+
|
|
658
|
+
if not validated_data:
|
|
659
|
+
return "Error: No valid data points after validation"
|
|
660
|
+
|
|
661
|
+
# Sanitize title
|
|
662
|
+
title = title.replace('"', "'").strip()
|
|
663
|
+
if not title:
|
|
664
|
+
title = "Pie Chart"
|
|
665
|
+
|
|
666
|
+
# Build diagram
|
|
667
|
+
data_lines = "\n".join(
|
|
668
|
+
[f' "{label}" : {value}' for label, value in validated_data.items()]
|
|
669
|
+
)
|
|
670
|
+
diagram = f"""---
|
|
671
|
+
title: {title}
|
|
672
|
+
---
|
|
673
|
+
pie
|
|
674
|
+
{data_lines}"""
|
|
675
|
+
|
|
676
|
+
return self._emit_diagram(diagram, "pie")
|
|
677
|
+
|
|
678
|
+
except Exception as e:
|
|
679
|
+
error_msg = f"Error creating pie chart: {str(e)}"
|
|
680
|
+
logger.error(f"[DataVisualization] {error_msg}", exc_info=True)
|
|
681
|
+
return error_msg
|
|
682
|
+
|
|
683
|
+
def create_state_diagram(
|
|
684
|
+
self,
|
|
685
|
+
title: str,
|
|
686
|
+
states: str,
|
|
687
|
+
) -> str:
|
|
688
|
+
"""
|
|
689
|
+
Create a state diagram.
|
|
690
|
+
|
|
691
|
+
Args:
|
|
692
|
+
title: Title of the state diagram
|
|
693
|
+
states: Mermaid state diagram definitions
|
|
694
|
+
|
|
695
|
+
Returns:
|
|
696
|
+
Success message with diagram event
|
|
697
|
+
|
|
698
|
+
Example:
|
|
699
|
+
create_state_diagram(
|
|
700
|
+
title="Order Processing States",
|
|
701
|
+
states='''
|
|
702
|
+
[*] --> Pending
|
|
703
|
+
Pending --> Processing : Payment received
|
|
704
|
+
Processing --> Shipped : Items packed
|
|
705
|
+
Shipped --> Delivered : Delivery confirmed
|
|
706
|
+
Delivered --> [*]
|
|
707
|
+
Processing --> Cancelled : Cancel request
|
|
708
|
+
Cancelled --> [*]
|
|
709
|
+
'''
|
|
710
|
+
)
|
|
711
|
+
"""
|
|
712
|
+
diagram = f"""---
|
|
713
|
+
title: {title}
|
|
714
|
+
---
|
|
715
|
+
stateDiagram-v2
|
|
716
|
+
{states.strip()}"""
|
|
717
|
+
return self._emit_diagram(diagram, "state")
|
|
718
|
+
|
|
719
|
+
def create_git_graph(
|
|
720
|
+
self,
|
|
721
|
+
title: str,
|
|
722
|
+
commits: str,
|
|
723
|
+
) -> str:
|
|
724
|
+
"""
|
|
725
|
+
Create a Git graph diagram.
|
|
726
|
+
|
|
727
|
+
Args:
|
|
728
|
+
title: Title of the Git graph
|
|
729
|
+
commits: Mermaid Git graph commit definitions
|
|
730
|
+
|
|
731
|
+
Returns:
|
|
732
|
+
Success message with diagram event
|
|
733
|
+
|
|
734
|
+
Example:
|
|
735
|
+
create_git_graph(
|
|
736
|
+
title="Feature Branch Workflow",
|
|
737
|
+
commits='''
|
|
738
|
+
commit
|
|
739
|
+
branch develop
|
|
740
|
+
checkout develop
|
|
741
|
+
commit
|
|
742
|
+
branch feature
|
|
743
|
+
checkout feature
|
|
744
|
+
commit
|
|
745
|
+
commit
|
|
746
|
+
checkout develop
|
|
747
|
+
merge feature
|
|
748
|
+
checkout main
|
|
749
|
+
merge develop
|
|
750
|
+
'''
|
|
751
|
+
)
|
|
752
|
+
"""
|
|
753
|
+
diagram = f"""---
|
|
754
|
+
title: {title}
|
|
755
|
+
---
|
|
756
|
+
gitGraph
|
|
757
|
+
{commits.strip()}"""
|
|
758
|
+
return self._emit_diagram(diagram, "git")
|
|
759
|
+
|
|
760
|
+
def create_user_journey(
|
|
761
|
+
self,
|
|
762
|
+
title: str,
|
|
763
|
+
journey: str,
|
|
764
|
+
) -> str:
|
|
765
|
+
"""
|
|
766
|
+
Create a user journey diagram.
|
|
767
|
+
|
|
768
|
+
Args:
|
|
769
|
+
title: Title of the user journey
|
|
770
|
+
journey: Mermaid user journey definitions
|
|
771
|
+
|
|
772
|
+
Returns:
|
|
773
|
+
Success message with diagram event
|
|
774
|
+
|
|
775
|
+
Example:
|
|
776
|
+
create_user_journey(
|
|
777
|
+
title="Customer Onboarding Journey",
|
|
778
|
+
journey='''
|
|
779
|
+
section Sign up
|
|
780
|
+
Visit website: 5: User
|
|
781
|
+
Create account: 3: User
|
|
782
|
+
section Getting Started
|
|
783
|
+
Complete profile: 4: User
|
|
784
|
+
First purchase: 5: User
|
|
785
|
+
'''
|
|
786
|
+
)
|
|
787
|
+
"""
|
|
788
|
+
diagram = f"""---
|
|
789
|
+
title: {title}
|
|
790
|
+
---
|
|
791
|
+
journey
|
|
792
|
+
{journey.strip()}"""
|
|
793
|
+
return self._emit_diagram(diagram, "journey")
|
|
794
|
+
|
|
795
|
+
def create_quadrant_chart(
|
|
796
|
+
self,
|
|
797
|
+
title: str,
|
|
798
|
+
x_axis: str,
|
|
799
|
+
y_axis: str,
|
|
800
|
+
items: str,
|
|
801
|
+
) -> str:
|
|
802
|
+
"""
|
|
803
|
+
Create a quadrant chart.
|
|
804
|
+
|
|
805
|
+
Args:
|
|
806
|
+
title: Title of the quadrant chart
|
|
807
|
+
x_axis: X-axis label (left --> right)
|
|
808
|
+
y_axis: Y-axis label (bottom --> top)
|
|
809
|
+
items: Mermaid quadrant chart item definitions
|
|
810
|
+
|
|
811
|
+
Returns:
|
|
812
|
+
Success message with diagram event
|
|
813
|
+
|
|
814
|
+
Example:
|
|
815
|
+
create_quadrant_chart(
|
|
816
|
+
title="Product Priority Matrix",
|
|
817
|
+
x_axis="Effort",
|
|
818
|
+
y_axis="Impact",
|
|
819
|
+
items='''
|
|
820
|
+
Feature A: [0.8, 0.9]
|
|
821
|
+
Feature B: [0.3, 0.7]
|
|
822
|
+
Feature C: [0.6, 0.4]
|
|
823
|
+
Feature D: [0.2, 0.2]
|
|
824
|
+
'''
|
|
825
|
+
)
|
|
826
|
+
"""
|
|
827
|
+
diagram = f"""---
|
|
828
|
+
title: {title}
|
|
829
|
+
---
|
|
830
|
+
quadrantChart
|
|
831
|
+
x-axis {x_axis}
|
|
832
|
+
y-axis {y_axis}
|
|
833
|
+
{items.strip()}"""
|
|
834
|
+
return self._emit_diagram(diagram, "quadrant")
|