kubiya-control-plane-api 0.1.0__py3-none-any.whl → 0.3.4__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.
Potentially problematic release.
This version of kubiya-control-plane-api might be problematic. Click here for more details.
- control_plane_api/README.md +266 -0
- control_plane_api/__init__.py +0 -0
- control_plane_api/__version__.py +1 -0
- control_plane_api/alembic/README +1 -0
- control_plane_api/alembic/env.py +98 -0
- control_plane_api/alembic/script.py.mako +28 -0
- control_plane_api/alembic/versions/1382bec74309_initial_migration_with_all_models.py +251 -0
- control_plane_api/alembic/versions/1f54bc2a37e3_add_analytics_tables.py +162 -0
- control_plane_api/alembic/versions/2e4cb136dc10_rename_toolset_ids_to_skill_ids_in_teams.py +30 -0
- control_plane_api/alembic/versions/31cd69a644ce_add_skill_templates_table.py +28 -0
- control_plane_api/alembic/versions/89e127caa47d_add_jobs_and_job_executions_tables.py +161 -0
- control_plane_api/alembic/versions/add_llm_models_table.py +51 -0
- control_plane_api/alembic/versions/b0e10697f212_add_runtime_column_to_teams_simple.py +42 -0
- control_plane_api/alembic/versions/ce43b24b63bf_add_execution_trigger_source_and_fix_.py +155 -0
- control_plane_api/alembic/versions/d4eaf16e3f8d_rename_toolsets_to_skills.py +84 -0
- control_plane_api/alembic/versions/efa2dc427da1_rename_metadata_to_custom_metadata.py +32 -0
- control_plane_api/alembic/versions/f973b431d1ce_add_workflow_executor_to_skill_types.py +44 -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 +379 -0
- control_plane_api/app/activities/team_activities.py +410 -0
- control_plane_api/app/activities/temporal_cloud_activities.py +577 -0
- control_plane_api/app/config/__init__.py +35 -0
- control_plane_api/app/config/api_config.py +354 -0
- control_plane_api/app/config/model_pricing.py +318 -0
- control_plane_api/app/config.py +95 -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/job_executor.py +312 -0
- control_plane_api/app/lib/kubiya_client.py +235 -0
- control_plane_api/app/lib/litellm_pricing.py +166 -0
- control_plane_api/app/lib/planning_tools/__init__.py +22 -0
- control_plane_api/app/lib/planning_tools/agents.py +155 -0
- control_plane_api/app/lib/planning_tools/base.py +189 -0
- control_plane_api/app/lib/planning_tools/environments.py +214 -0
- control_plane_api/app/lib/planning_tools/resources.py +240 -0
- control_plane_api/app/lib/planning_tools/teams.py +198 -0
- control_plane_api/app/lib/policy_enforcer_client.py +939 -0
- control_plane_api/app/lib/redis_client.py +436 -0
- control_plane_api/app/lib/supabase.py +71 -0
- control_plane_api/app/lib/temporal_client.py +138 -0
- control_plane_api/app/lib/validation/__init__.py +20 -0
- control_plane_api/app/lib/validation/runtime_validation.py +287 -0
- control_plane_api/app/main.py +128 -0
- control_plane_api/app/middleware/__init__.py +8 -0
- control_plane_api/app/middleware/auth.py +513 -0
- control_plane_api/app/middleware/exception_handler.py +267 -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 +27 -0
- control_plane_api/app/models/agent.py +79 -0
- control_plane_api/app/models/analytics.py +206 -0
- control_plane_api/app/models/associations.py +81 -0
- control_plane_api/app/models/environment.py +63 -0
- control_plane_api/app/models/execution.py +93 -0
- control_plane_api/app/models/job.py +179 -0
- control_plane_api/app/models/llm_model.py +75 -0
- control_plane_api/app/models/presence.py +49 -0
- control_plane_api/app/models/project.py +47 -0
- control_plane_api/app/models/session.py +38 -0
- control_plane_api/app/models/team.py +66 -0
- control_plane_api/app/models/workflow.py +55 -0
- control_plane_api/app/policies/README.md +121 -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_restrictions.rego +86 -0
- control_plane_api/app/routers/__init__.py +4 -0
- control_plane_api/app/routers/agents.py +364 -0
- control_plane_api/app/routers/agents_v2.py +1260 -0
- control_plane_api/app/routers/analytics.py +1014 -0
- control_plane_api/app/routers/context_manager.py +562 -0
- control_plane_api/app/routers/environment_context.py +270 -0
- control_plane_api/app/routers/environments.py +715 -0
- control_plane_api/app/routers/execution_environment.py +517 -0
- control_plane_api/app/routers/executions.py +1911 -0
- control_plane_api/app/routers/health.py +92 -0
- control_plane_api/app/routers/health_v2.py +326 -0
- control_plane_api/app/routers/integrations.py +274 -0
- control_plane_api/app/routers/jobs.py +1344 -0
- control_plane_api/app/routers/models.py +82 -0
- control_plane_api/app/routers/models_v2.py +361 -0
- control_plane_api/app/routers/policies.py +639 -0
- control_plane_api/app/routers/presence.py +234 -0
- control_plane_api/app/routers/projects.py +902 -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 +155 -0
- control_plane_api/app/routers/skills.py +1001 -0
- control_plane_api/app/routers/skills_definitions.py +140 -0
- control_plane_api/app/routers/task_planning.py +1256 -0
- control_plane_api/app/routers/task_queues.py +654 -0
- control_plane_api/app/routers/team_context.py +270 -0
- control_plane_api/app/routers/teams.py +1400 -0
- control_plane_api/app/routers/worker_queues.py +1545 -0
- control_plane_api/app/routers/workers.py +935 -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/job_schemas.py +295 -0
- control_plane_api/app/services/__init__.py +1 -0
- control_plane_api/app/services/agno_service.py +619 -0
- control_plane_api/app/services/litellm_service.py +190 -0
- control_plane_api/app/services/policy_service.py +525 -0
- control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
- control_plane_api/app/skills/__init__.py +44 -0
- control_plane_api/app/skills/base.py +229 -0
- control_plane_api/app/skills/business_intelligence.py +189 -0
- control_plane_api/app/skills/data_visualization.py +154 -0
- control_plane_api/app/skills/docker.py +104 -0
- control_plane_api/app/skills/file_generation.py +94 -0
- control_plane_api/app/skills/file_system.py +110 -0
- control_plane_api/app/skills/python.py +92 -0
- control_plane_api/app/skills/registry.py +65 -0
- control_plane_api/app/skills/shell.py +102 -0
- control_plane_api/app/skills/workflow_executor.py +469 -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 +507 -0
- control_plane_api/app/workflows/agent_execution_with_skills.py +222 -0
- control_plane_api/app/workflows/namespace_provisioning.py +326 -0
- control_plane_api/app/workflows/team_execution.py +399 -0
- control_plane_api/scripts/seed_models.py +239 -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 +1241 -0
- control_plane_api/worker/activities/approval_activities.py +234 -0
- control_plane_api/worker/activities/runtime_activities.py +388 -0
- control_plane_api/worker/activities/skill_activities.py +267 -0
- control_plane_api/worker/activities/team_activities.py +1217 -0
- control_plane_api/worker/config/__init__.py +31 -0
- control_plane_api/worker/config/worker_config.py +275 -0
- control_plane_api/worker/control_plane_client.py +529 -0
- control_plane_api/worker/examples/analytics_integration_example.py +362 -0
- control_plane_api/worker/models/__init__.py +1 -0
- control_plane_api/worker/models/inputs.py +89 -0
- control_plane_api/worker/runtimes/__init__.py +31 -0
- control_plane_api/worker/runtimes/base.py +789 -0
- control_plane_api/worker/runtimes/claude_code_runtime.py +1443 -0
- control_plane_api/worker/runtimes/default_runtime.py +617 -0
- control_plane_api/worker/runtimes/factory.py +173 -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_executor.py +422 -0
- control_plane_api/worker/services/agent_executor_v2.py +383 -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/data_visualization.py +827 -0
- control_plane_api/worker/services/jira_tools.py +257 -0
- control_plane_api/worker/services/runtime_analytics.py +328 -0
- control_plane_api/worker/services/session_service.py +194 -0
- control_plane_api/worker/services/skill_factory.py +175 -0
- control_plane_api/worker/services/team_executor.py +574 -0
- control_plane_api/worker/services/team_executor_v2.py +465 -0
- control_plane_api/worker/services/workflow_executor_tools.py +1418 -0
- control_plane_api/worker/tests/__init__.py +1 -0
- control_plane_api/worker/tests/e2e/__init__.py +0 -0
- control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
- control_plane_api/worker/tests/integration/__init__.py +0 -0
- control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
- control_plane_api/worker/tests/unit/__init__.py +0 -0
- control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
- control_plane_api/worker/utils/__init__.py +1 -0
- control_plane_api/worker/utils/chunk_batcher.py +305 -0
- control_plane_api/worker/utils/retry_utils.py +60 -0
- control_plane_api/worker/utils/streaming_utils.py +373 -0
- control_plane_api/worker/worker.py +753 -0
- control_plane_api/worker/workflows/__init__.py +0 -0
- control_plane_api/worker/workflows/agent_execution.py +589 -0
- control_plane_api/worker/workflows/team_execution.py +429 -0
- kubiya_control_plane_api-0.3.4.dist-info/METADATA +229 -0
- kubiya_control_plane_api-0.3.4.dist-info/RECORD +182 -0
- kubiya_control_plane_api-0.3.4.dist-info/entry_points.txt +2 -0
- kubiya_control_plane_api-0.3.4.dist-info/top_level.txt +1 -0
- kubiya_control_plane_api-0.1.0.dist-info/METADATA +0 -66
- kubiya_control_plane_api-0.1.0.dist-info/RECORD +0 -5
- kubiya_control_plane_api-0.1.0.dist-info/top_level.txt +0 -1
- {kubiya_control_plane_api-0.1.0.dist-info/licenses → control_plane_api}/LICENSE +0 -0
- {kubiya_control_plane_api-0.1.0.dist-info → kubiya_control_plane_api-0.3.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Temporal Cloud Provisioning Service
|
|
3
|
+
|
|
4
|
+
This service handles provisioning Temporal Cloud namespaces via the
|
|
5
|
+
Vercel serverless function (api/provision-namespace.go).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import httpx
|
|
10
|
+
import structlog
|
|
11
|
+
from typing import Dict, Any
|
|
12
|
+
|
|
13
|
+
logger = structlog.get_logger()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TemporalCloudProvisioningService:
|
|
17
|
+
"""Service for provisioning Temporal Cloud namespaces"""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
# Get the Vercel function URL from environment
|
|
21
|
+
self.proxy_url = os.getenv("TEMPORAL_CLOUD_PROXY_URL")
|
|
22
|
+
if not self.proxy_url:
|
|
23
|
+
# If not set, use the Vercel production URL
|
|
24
|
+
self.proxy_url = "https://temporal-cloud-proxy.vercel.app/api/provision-namespace"
|
|
25
|
+
|
|
26
|
+
# Get the admin token for authorization (will be checked when actually used)
|
|
27
|
+
self.admin_token = os.getenv("TEMPORAL_CLOUD_ADMIN_TOKEN")
|
|
28
|
+
|
|
29
|
+
async def provision_namespace_for_organization(
|
|
30
|
+
self,
|
|
31
|
+
organization_id: str,
|
|
32
|
+
organization_name: str,
|
|
33
|
+
region: str = "aws-us-east-1",
|
|
34
|
+
retention_days: int = 7,
|
|
35
|
+
) -> Dict[str, Any]:
|
|
36
|
+
"""
|
|
37
|
+
Provision a Temporal Cloud namespace for an organization.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
organization_id: The organization ID
|
|
41
|
+
organization_name: The organization name
|
|
42
|
+
region: The Temporal Cloud region (default: aws-us-east-1)
|
|
43
|
+
retention_days: Number of days to retain workflow history (default: 7)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Dictionary with:
|
|
47
|
+
- success: Boolean indicating if provisioning succeeded
|
|
48
|
+
- namespace_name: The provisioned namespace name
|
|
49
|
+
- namespace: Dictionary with namespace details
|
|
50
|
+
- already_exists: Boolean indicating if namespace already existed
|
|
51
|
+
- error: Error message if failed
|
|
52
|
+
- timeout: Boolean indicating if operation timed out
|
|
53
|
+
"""
|
|
54
|
+
logger.info(
|
|
55
|
+
"provisioning_temporal_namespace",
|
|
56
|
+
organization_id=organization_id,
|
|
57
|
+
organization_name=organization_name,
|
|
58
|
+
region=region,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Check if token is available
|
|
62
|
+
if not self.admin_token:
|
|
63
|
+
error_msg = "TEMPORAL_CLOUD_ADMIN_TOKEN environment variable is required but not set"
|
|
64
|
+
logger.error("temporal_cloud_token_missing", organization_id=organization_id)
|
|
65
|
+
return {
|
|
66
|
+
"success": False,
|
|
67
|
+
"error": error_msg,
|
|
68
|
+
"timeout": False,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
# Prepare the request
|
|
73
|
+
payload = {
|
|
74
|
+
"organization_id": organization_id,
|
|
75
|
+
"organization_name": organization_name,
|
|
76
|
+
"region": region,
|
|
77
|
+
"retention_days": retention_days,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
headers = {
|
|
81
|
+
"Authorization": f"Bearer {self.admin_token}",
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Call the Vercel function
|
|
86
|
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
87
|
+
response = await client.post(
|
|
88
|
+
self.proxy_url,
|
|
89
|
+
json=payload,
|
|
90
|
+
headers=headers,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Check response status
|
|
94
|
+
if response.status_code == 200:
|
|
95
|
+
result = response.json()
|
|
96
|
+
logger.info(
|
|
97
|
+
"namespace_provisioned_successfully",
|
|
98
|
+
organization_id=organization_id,
|
|
99
|
+
namespace_name=result.get("namespace_name"),
|
|
100
|
+
already_exists=result.get("already_exists", False),
|
|
101
|
+
)
|
|
102
|
+
return result
|
|
103
|
+
else:
|
|
104
|
+
error_msg = response.text
|
|
105
|
+
logger.error(
|
|
106
|
+
"namespace_provisioning_failed",
|
|
107
|
+
organization_id=organization_id,
|
|
108
|
+
status_code=response.status_code,
|
|
109
|
+
error=error_msg,
|
|
110
|
+
)
|
|
111
|
+
return {
|
|
112
|
+
"success": False,
|
|
113
|
+
"error": f"HTTP {response.status_code}: {error_msg}",
|
|
114
|
+
"timeout": False,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
except httpx.TimeoutException as e:
|
|
118
|
+
logger.warning(
|
|
119
|
+
"namespace_provisioning_timeout",
|
|
120
|
+
organization_id=organization_id,
|
|
121
|
+
error=str(e),
|
|
122
|
+
)
|
|
123
|
+
return {
|
|
124
|
+
"success": False,
|
|
125
|
+
"error": "Provisioning timed out",
|
|
126
|
+
"timeout": True,
|
|
127
|
+
}
|
|
128
|
+
except Exception as e:
|
|
129
|
+
logger.error(
|
|
130
|
+
"namespace_provisioning_exception",
|
|
131
|
+
organization_id=organization_id,
|
|
132
|
+
error=str(e),
|
|
133
|
+
)
|
|
134
|
+
return {
|
|
135
|
+
"success": False,
|
|
136
|
+
"error": str(e),
|
|
137
|
+
"timeout": False,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Global instance
|
|
142
|
+
_provisioning_service = None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_provisioning_service() -> TemporalCloudProvisioningService:
|
|
146
|
+
"""Get the provisioning service singleton"""
|
|
147
|
+
global _provisioning_service
|
|
148
|
+
if _provisioning_service is None:
|
|
149
|
+
_provisioning_service = TemporalCloudProvisioningService()
|
|
150
|
+
return _provisioning_service
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Skills Module
|
|
3
|
+
|
|
4
|
+
This module manages all available skills (OS-level capabilities) that can be
|
|
5
|
+
assigned to agents and teams. Each skill corresponds to a capability that agents
|
|
6
|
+
can use during execution (file system, shell, Docker, Python, etc.).
|
|
7
|
+
|
|
8
|
+
Skills are defined as Python classes that provide:
|
|
9
|
+
- Metadata (name, description, icon)
|
|
10
|
+
- Default configuration
|
|
11
|
+
- Validation logic
|
|
12
|
+
- Instantiation logic for the underlying framework
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from .base import SkillDefinition, SkillType, SkillCategory, SkillRequirements, SkillVariant
|
|
16
|
+
from .registry import skill_registry, get_skill, get_all_skills, register_skill
|
|
17
|
+
|
|
18
|
+
# Import all skill definitions to auto-register them
|
|
19
|
+
from .file_system import FileSystemSkill
|
|
20
|
+
from .shell import ShellSkill
|
|
21
|
+
from .docker import DockerSkill
|
|
22
|
+
from .python import PythonSkill
|
|
23
|
+
from .file_generation import FileGenerationSkill
|
|
24
|
+
from .data_visualization import DataVisualizationSkill
|
|
25
|
+
from .workflow_executor import WorkflowExecutorSkill
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"SkillDefinition",
|
|
29
|
+
"SkillType",
|
|
30
|
+
"SkillCategory",
|
|
31
|
+
"SkillRequirements",
|
|
32
|
+
"SkillVariant",
|
|
33
|
+
"skill_registry",
|
|
34
|
+
"get_skill",
|
|
35
|
+
"get_all_skills",
|
|
36
|
+
"register_skill",
|
|
37
|
+
"FileSystemSkill",
|
|
38
|
+
"ShellSkill",
|
|
39
|
+
"DockerSkill",
|
|
40
|
+
"PythonSkill",
|
|
41
|
+
"FileGenerationSkill",
|
|
42
|
+
"DataVisualizationSkill",
|
|
43
|
+
"WorkflowExecutorSkill",
|
|
44
|
+
]
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base classes for skill definitions
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, Any, List, Optional, Set
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
import platform
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SkillType(str, Enum):
|
|
12
|
+
"""Supported skill types"""
|
|
13
|
+
FILE_SYSTEM = "file_system"
|
|
14
|
+
SHELL = "shell"
|
|
15
|
+
DOCKER = "docker"
|
|
16
|
+
PYTHON = "python"
|
|
17
|
+
FILE_GENERATION = "file_generation"
|
|
18
|
+
DATA_VISUALIZATION = "data_visualization"
|
|
19
|
+
SLEEP = "sleep"
|
|
20
|
+
WORKFLOW_EXECUTOR = "workflow_executor"
|
|
21
|
+
CUSTOM = "custom"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SkillCategory(str, Enum):
|
|
25
|
+
"""Skill categories for organization"""
|
|
26
|
+
COMMON = "common" # Frequently used, safe defaults
|
|
27
|
+
ADVANCED = "advanced" # Advanced features, require more privileges
|
|
28
|
+
SECURITY = "security" # Security-focused, restricted access
|
|
29
|
+
CUSTOM = "custom" # User-defined custom skills
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SkillRequirements(BaseModel):
|
|
33
|
+
"""Runtime requirements for a skill"""
|
|
34
|
+
# Python packages required (will be checked/installed by worker)
|
|
35
|
+
python_packages: List[str] = Field(default_factory=list)
|
|
36
|
+
|
|
37
|
+
# System packages required (informational, worker should validate)
|
|
38
|
+
system_packages: List[str] = Field(default_factory=list)
|
|
39
|
+
|
|
40
|
+
# Supported operating systems (e.g., ["linux", "darwin", "windows"])
|
|
41
|
+
supported_os: Optional[List[str]] = None
|
|
42
|
+
|
|
43
|
+
# Minimum Python version (e.g., "3.10")
|
|
44
|
+
min_python_version: Optional[str] = None
|
|
45
|
+
|
|
46
|
+
# Environment variables required
|
|
47
|
+
required_env_vars: List[str] = Field(default_factory=list)
|
|
48
|
+
|
|
49
|
+
# External services/APIs required (informational)
|
|
50
|
+
external_dependencies: List[str] = Field(default_factory=list)
|
|
51
|
+
|
|
52
|
+
# Additional notes about requirements
|
|
53
|
+
notes: Optional[str] = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class SkillVariant(BaseModel):
|
|
57
|
+
"""A specific variant/preset of a skill"""
|
|
58
|
+
id: str
|
|
59
|
+
name: str
|
|
60
|
+
description: str
|
|
61
|
+
category: SkillCategory
|
|
62
|
+
configuration: Dict[str, Any]
|
|
63
|
+
badge: Optional[str] = None # e.g., "Safe", "Recommended", "Advanced"
|
|
64
|
+
icon: Optional[str] = None
|
|
65
|
+
is_default: bool = False
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class SkillDefinition(ABC):
|
|
69
|
+
"""
|
|
70
|
+
Base class for all skill definitions.
|
|
71
|
+
|
|
72
|
+
Each skill type should subclass this and implement the required methods.
|
|
73
|
+
This provides a clean interface for defining new skills.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
@abstractmethod
|
|
78
|
+
def type(self) -> SkillType:
|
|
79
|
+
"""The type identifier for this skill"""
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
@abstractmethod
|
|
84
|
+
def name(self) -> str:
|
|
85
|
+
"""Human-readable name"""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def description(self) -> str:
|
|
91
|
+
"""Description of what this skill does"""
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
@abstractmethod
|
|
96
|
+
def icon(self) -> str:
|
|
97
|
+
"""Icon name (Lucide or React Icons)"""
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def icon_type(self) -> str:
|
|
102
|
+
"""Icon type: 'lucide' or 'react-icon'"""
|
|
103
|
+
return "lucide"
|
|
104
|
+
|
|
105
|
+
@abstractmethod
|
|
106
|
+
def get_variants(self) -> List[SkillVariant]:
|
|
107
|
+
"""
|
|
108
|
+
Get all predefined variants/presets for this skill.
|
|
109
|
+
|
|
110
|
+
Returns a list of variants with different configurations
|
|
111
|
+
(e.g., "Read Only", "Full Access", "Sandboxed")
|
|
112
|
+
"""
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
@abstractmethod
|
|
116
|
+
def validate_configuration(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
117
|
+
"""
|
|
118
|
+
Validate and normalize configuration.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
config: Raw configuration dict
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Validated and normalized configuration
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
ValueError: If configuration is invalid
|
|
128
|
+
"""
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
@abstractmethod
|
|
132
|
+
def get_default_configuration(self) -> Dict[str, Any]:
|
|
133
|
+
"""Get the default configuration for this skill"""
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
def get_framework_class_name(self) -> str:
|
|
137
|
+
"""
|
|
138
|
+
Get the underlying framework tool class name.
|
|
139
|
+
This is used for instantiation during agent execution.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Class name (e.g., "FileTools", "ShellTools")
|
|
143
|
+
"""
|
|
144
|
+
# Default mapping based on type
|
|
145
|
+
mapping = {
|
|
146
|
+
SkillType.FILE_SYSTEM: "FileTools",
|
|
147
|
+
SkillType.SHELL: "ShellTools",
|
|
148
|
+
SkillType.DOCKER: "DockerTools",
|
|
149
|
+
SkillType.PYTHON: "PythonTools",
|
|
150
|
+
SkillType.FILE_GENERATION: "FileGenerationTools",
|
|
151
|
+
SkillType.DATA_VISUALIZATION: "DataVisualizationTools",
|
|
152
|
+
SkillType.SLEEP: "SleepTools",
|
|
153
|
+
}
|
|
154
|
+
return mapping.get(self.type, "BaseTool")
|
|
155
|
+
|
|
156
|
+
def get_requirements(self) -> SkillRequirements:
|
|
157
|
+
"""
|
|
158
|
+
Get runtime requirements for this skill.
|
|
159
|
+
|
|
160
|
+
Override this method to specify requirements like:
|
|
161
|
+
- Python packages
|
|
162
|
+
- System packages
|
|
163
|
+
- OS requirements
|
|
164
|
+
- Environment variables
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
SkillRequirements instance
|
|
168
|
+
"""
|
|
169
|
+
# Default: no special requirements
|
|
170
|
+
return SkillRequirements()
|
|
171
|
+
|
|
172
|
+
def check_requirements(self) -> tuple[bool, List[str]]:
|
|
173
|
+
"""
|
|
174
|
+
Check if requirements are met in current environment.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Tuple of (is_satisfied, missing_requirements)
|
|
178
|
+
"""
|
|
179
|
+
requirements = self.get_requirements()
|
|
180
|
+
missing = []
|
|
181
|
+
|
|
182
|
+
# Check OS
|
|
183
|
+
if requirements.supported_os:
|
|
184
|
+
current_os = platform.system().lower()
|
|
185
|
+
if current_os not in requirements.supported_os:
|
|
186
|
+
missing.append(f"OS '{current_os}' not supported (requires: {', '.join(requirements.supported_os)})")
|
|
187
|
+
|
|
188
|
+
# Check Python version
|
|
189
|
+
if requirements.min_python_version:
|
|
190
|
+
import sys
|
|
191
|
+
from packaging import version
|
|
192
|
+
current_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
193
|
+
if version.parse(current_version) < version.parse(requirements.min_python_version):
|
|
194
|
+
missing.append(f"Python {requirements.min_python_version}+ required (current: {current_version})")
|
|
195
|
+
|
|
196
|
+
# Check environment variables
|
|
197
|
+
import os
|
|
198
|
+
for env_var in requirements.required_env_vars:
|
|
199
|
+
if not os.getenv(env_var):
|
|
200
|
+
missing.append(f"Environment variable '{env_var}' not set")
|
|
201
|
+
|
|
202
|
+
# Check Python packages (basic import check)
|
|
203
|
+
for package in requirements.python_packages:
|
|
204
|
+
package_name = package.split('[')[0].split('>=')[0].split('==')[0].strip()
|
|
205
|
+
try:
|
|
206
|
+
__import__(package_name)
|
|
207
|
+
except ImportError:
|
|
208
|
+
missing.append(f"Python package '{package}' not installed")
|
|
209
|
+
|
|
210
|
+
return len(missing) == 0, missing
|
|
211
|
+
|
|
212
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
213
|
+
"""Convert to dictionary representation"""
|
|
214
|
+
requirements = self.get_requirements()
|
|
215
|
+
is_satisfied, missing = self.check_requirements()
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
"type": self.type.value,
|
|
219
|
+
"name": self.name,
|
|
220
|
+
"description": self.description,
|
|
221
|
+
"icon": self.icon,
|
|
222
|
+
"icon_type": self.icon_type,
|
|
223
|
+
"default_configuration": self.get_default_configuration(),
|
|
224
|
+
"variants": [v.model_dump() for v in self.get_variants()],
|
|
225
|
+
"framework_class": self.get_framework_class_name(),
|
|
226
|
+
"requirements": requirements.model_dump(),
|
|
227
|
+
"requirements_satisfied": is_satisfied,
|
|
228
|
+
"missing_requirements": missing,
|
|
229
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Business Intelligence Skill
|
|
3
|
+
|
|
4
|
+
Provides comprehensive BI capabilities including database querying, analytics,
|
|
5
|
+
visualization generation, and multi-agent analysis. Supports PostgreSQL, MySQL,
|
|
6
|
+
MongoDB, and file-based data sources (CSV, JSON, Parquet, Excel).
|
|
7
|
+
"""
|
|
8
|
+
from typing import Dict, Any, List
|
|
9
|
+
from .base import SkillDefinition, SkillType, SkillCategory, SkillVariant
|
|
10
|
+
from .registry import register_skill
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BusinessIntelligenceSkill(SkillDefinition):
|
|
14
|
+
"""Business Intelligence and Analytics skill"""
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def type(self) -> SkillType:
|
|
18
|
+
return SkillType.BUSINESS_INTELLIGENCE
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def name(self) -> str:
|
|
22
|
+
return "Business Intelligence"
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def description(self) -> str:
|
|
26
|
+
return "Advanced BI and analytics with multi-agent analysis, database querying, and interactive visualizations"
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def icon(self) -> str:
|
|
30
|
+
return "BarChart"
|
|
31
|
+
|
|
32
|
+
def get_variants(self) -> List[SkillVariant]:
|
|
33
|
+
return [
|
|
34
|
+
SkillVariant(
|
|
35
|
+
id="bi_full",
|
|
36
|
+
name="Full BI Suite",
|
|
37
|
+
description="Complete BI capabilities with all data sources and analytics features",
|
|
38
|
+
category=SkillCategory.ADVANCED,
|
|
39
|
+
badge="Recommended",
|
|
40
|
+
icon="BarChart",
|
|
41
|
+
configuration={
|
|
42
|
+
"data_sources": [
|
|
43
|
+
{
|
|
44
|
+
"id": "default_postgres",
|
|
45
|
+
"name": "PostgreSQL Database",
|
|
46
|
+
"type": "postgresql",
|
|
47
|
+
"connection": {
|
|
48
|
+
"host": "${POSTGRES_HOST}",
|
|
49
|
+
"port": "${POSTGRES_PORT:5432}",
|
|
50
|
+
"database": "${POSTGRES_DB}",
|
|
51
|
+
"username": "${POSTGRES_USER}",
|
|
52
|
+
"password": "${POSTGRES_PASSWORD}",
|
|
53
|
+
"ssl": True,
|
|
54
|
+
"pool_size": 5
|
|
55
|
+
},
|
|
56
|
+
"query_limits": {
|
|
57
|
+
"max_rows": 10000,
|
|
58
|
+
"timeout_seconds": 30
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"security": {
|
|
63
|
+
"allowed_sql_commands": ["SELECT"],
|
|
64
|
+
"deny_patterns": ["DROP", "DELETE", "TRUNCATE", "ALTER", "INSERT", "UPDATE"]
|
|
65
|
+
},
|
|
66
|
+
"features": {
|
|
67
|
+
"enable_multi_agent": True,
|
|
68
|
+
"enable_visualizations": True,
|
|
69
|
+
"enable_schema_introspection": True,
|
|
70
|
+
"enable_query_validation": True
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
is_default=True,
|
|
74
|
+
),
|
|
75
|
+
SkillVariant(
|
|
76
|
+
id="bi_read_only",
|
|
77
|
+
name="Read-Only BI",
|
|
78
|
+
description="Safe, read-only analytics with SELECT-only permissions",
|
|
79
|
+
category=SkillCategory.COMMON,
|
|
80
|
+
badge="Safe",
|
|
81
|
+
icon="Eye",
|
|
82
|
+
configuration={
|
|
83
|
+
"data_sources": [], # Configured per agent
|
|
84
|
+
"security": {
|
|
85
|
+
"allowed_sql_commands": ["SELECT"],
|
|
86
|
+
"deny_patterns": ["DROP", "DELETE", "TRUNCATE", "ALTER", "INSERT", "UPDATE", "CREATE"]
|
|
87
|
+
},
|
|
88
|
+
"features": {
|
|
89
|
+
"enable_multi_agent": True,
|
|
90
|
+
"enable_visualizations": True,
|
|
91
|
+
"enable_schema_introspection": True,
|
|
92
|
+
"enable_query_validation": True
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
is_default=False,
|
|
96
|
+
),
|
|
97
|
+
SkillVariant(
|
|
98
|
+
id="bi_file_analysis",
|
|
99
|
+
name="File Analysis",
|
|
100
|
+
description="Analyze CSV, JSON, Parquet, and Excel files without database access",
|
|
101
|
+
category=SkillCategory.COMMON,
|
|
102
|
+
badge="Simple",
|
|
103
|
+
icon="FileSpreadsheet",
|
|
104
|
+
configuration={
|
|
105
|
+
"data_sources": [],
|
|
106
|
+
"security": {
|
|
107
|
+
"allowed_sql_commands": ["SELECT"],
|
|
108
|
+
"deny_patterns": []
|
|
109
|
+
},
|
|
110
|
+
"features": {
|
|
111
|
+
"enable_multi_agent": True,
|
|
112
|
+
"enable_visualizations": True,
|
|
113
|
+
"enable_schema_introspection": True,
|
|
114
|
+
"enable_query_validation": False,
|
|
115
|
+
"supported_formats": ["csv", "json", "parquet", "excel"]
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
is_default=False,
|
|
119
|
+
),
|
|
120
|
+
SkillVariant(
|
|
121
|
+
id="bi_custom",
|
|
122
|
+
name="Custom BI Configuration",
|
|
123
|
+
description="Fully customizable BI setup with user-defined data sources and security policies",
|
|
124
|
+
category=SkillCategory.ADVANCED,
|
|
125
|
+
badge="Flexible",
|
|
126
|
+
icon="Settings",
|
|
127
|
+
configuration={
|
|
128
|
+
"data_sources": [],
|
|
129
|
+
"security": {
|
|
130
|
+
"allowed_sql_commands": ["SELECT"],
|
|
131
|
+
"deny_patterns": []
|
|
132
|
+
},
|
|
133
|
+
"features": {
|
|
134
|
+
"enable_multi_agent": True,
|
|
135
|
+
"enable_visualizations": True,
|
|
136
|
+
"enable_schema_introspection": True,
|
|
137
|
+
"enable_query_validation": True
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
is_default=False,
|
|
141
|
+
),
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
def validate_configuration(self, config: Dict[str, Any]) -> bool:
|
|
145
|
+
"""Validate BI skill configuration"""
|
|
146
|
+
required_keys = ["data_sources", "security", "features"]
|
|
147
|
+
|
|
148
|
+
# Check required top-level keys
|
|
149
|
+
for key in required_keys:
|
|
150
|
+
if key not in config:
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
# Validate security config
|
|
154
|
+
if "security" in config:
|
|
155
|
+
security = config["security"]
|
|
156
|
+
if "allowed_sql_commands" not in security:
|
|
157
|
+
return False
|
|
158
|
+
if not isinstance(security["allowed_sql_commands"], list):
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
# Validate data sources
|
|
162
|
+
if "data_sources" in config:
|
|
163
|
+
for ds in config["data_sources"]:
|
|
164
|
+
if "id" not in ds or "type" not in ds:
|
|
165
|
+
return False
|
|
166
|
+
if "connection" not in ds:
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
def get_default_configuration(self) -> Dict[str, Any]:
|
|
172
|
+
"""Get default configuration for BI skill"""
|
|
173
|
+
return {
|
|
174
|
+
"data_sources": [],
|
|
175
|
+
"security": {
|
|
176
|
+
"allowed_sql_commands": ["SELECT"],
|
|
177
|
+
"deny_patterns": ["DROP", "DELETE", "TRUNCATE", "ALTER", "INSERT", "UPDATE"]
|
|
178
|
+
},
|
|
179
|
+
"features": {
|
|
180
|
+
"enable_multi_agent": True,
|
|
181
|
+
"enable_visualizations": True,
|
|
182
|
+
"enable_schema_introspection": True,
|
|
183
|
+
"enable_query_validation": True
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# Register the skill
|
|
189
|
+
register_skill(BusinessIntelligenceToolSet())
|