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,194 @@
|
|
|
1
|
+
"""Session management service - handles loading and persisting conversation history"""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any, Optional
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
import structlog
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from control_plane_api.worker.control_plane_client import ControlPlaneClient
|
|
9
|
+
from control_plane_api.worker.utils.retry_utils import retry_with_backoff
|
|
10
|
+
|
|
11
|
+
logger = structlog.get_logger()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _safe_timestamp_to_iso(timestamp: Any) -> str:
|
|
15
|
+
"""
|
|
16
|
+
Safely convert a timestamp (int, float, datetime, or str) to ISO format string.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
timestamp: Can be Unix timestamp (int/float), datetime object, or ISO string
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
ISO format timestamp string
|
|
23
|
+
"""
|
|
24
|
+
if isinstance(timestamp, str):
|
|
25
|
+
# Already a string, return as-is
|
|
26
|
+
return timestamp
|
|
27
|
+
elif isinstance(timestamp, datetime):
|
|
28
|
+
# datetime object, call isoformat()
|
|
29
|
+
return timestamp.isoformat()
|
|
30
|
+
elif isinstance(timestamp, (int, float)):
|
|
31
|
+
# Unix timestamp, convert to datetime first
|
|
32
|
+
return datetime.fromtimestamp(timestamp, tz=timezone.utc).isoformat()
|
|
33
|
+
else:
|
|
34
|
+
# Fallback to current time
|
|
35
|
+
return datetime.now(timezone.utc).isoformat()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class SessionService:
|
|
39
|
+
"""
|
|
40
|
+
Manages session history loading and persistence via Control Plane API.
|
|
41
|
+
|
|
42
|
+
Workers don't have database access, so all session operations go through
|
|
43
|
+
the Control Plane which provides Redis caching for hot loads.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, control_plane: ControlPlaneClient):
|
|
47
|
+
self.control_plane = control_plane
|
|
48
|
+
|
|
49
|
+
@retry_with_backoff(max_retries=3, initial_delay=1.0)
|
|
50
|
+
def load_session(
|
|
51
|
+
self,
|
|
52
|
+
execution_id: str,
|
|
53
|
+
session_id: Optional[str] = None
|
|
54
|
+
) -> List[Dict[str, Any]]:
|
|
55
|
+
"""
|
|
56
|
+
Load session history from Control Plane (with retry).
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
List of message dicts with role, content, timestamp, etc.
|
|
60
|
+
Empty list if session not found or on error.
|
|
61
|
+
"""
|
|
62
|
+
if not session_id:
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
session_data = self.control_plane.get_session(
|
|
67
|
+
execution_id=execution_id,
|
|
68
|
+
session_id=session_id
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if session_data and session_data.get("messages"):
|
|
72
|
+
messages = session_data["messages"]
|
|
73
|
+
logger.info(
|
|
74
|
+
"session_loaded",
|
|
75
|
+
execution_id=execution_id[:8],
|
|
76
|
+
message_count=len(messages)
|
|
77
|
+
)
|
|
78
|
+
return messages
|
|
79
|
+
|
|
80
|
+
return []
|
|
81
|
+
|
|
82
|
+
except httpx.TimeoutException:
|
|
83
|
+
logger.warning(
|
|
84
|
+
"session_load_timeout",
|
|
85
|
+
execution_id=execution_id[:8]
|
|
86
|
+
)
|
|
87
|
+
raise # Let retry decorator handle it
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.warning(
|
|
90
|
+
"session_load_error",
|
|
91
|
+
execution_id=execution_id[:8],
|
|
92
|
+
error=str(e)
|
|
93
|
+
)
|
|
94
|
+
return [] # Don't retry on non-timeout errors
|
|
95
|
+
|
|
96
|
+
@retry_with_backoff(max_retries=3, initial_delay=1.0)
|
|
97
|
+
def persist_session(
|
|
98
|
+
self,
|
|
99
|
+
execution_id: str,
|
|
100
|
+
session_id: str,
|
|
101
|
+
user_id: Optional[str],
|
|
102
|
+
messages: List[Dict[str, Any]],
|
|
103
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
104
|
+
) -> bool:
|
|
105
|
+
"""
|
|
106
|
+
Persist session history to Control Plane (with retry).
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
True if successful, False otherwise
|
|
110
|
+
"""
|
|
111
|
+
if not messages:
|
|
112
|
+
logger.info("session_persist_skipped_no_messages", execution_id=execution_id[:8])
|
|
113
|
+
return True
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
success = self.control_plane.persist_session(
|
|
117
|
+
execution_id=execution_id,
|
|
118
|
+
session_id=session_id or execution_id,
|
|
119
|
+
user_id=user_id,
|
|
120
|
+
messages=messages,
|
|
121
|
+
metadata=metadata or {}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if success:
|
|
125
|
+
logger.info(
|
|
126
|
+
"session_persisted",
|
|
127
|
+
execution_id=execution_id[:8],
|
|
128
|
+
message_count=len(messages)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
return success
|
|
132
|
+
|
|
133
|
+
except Exception as e:
|
|
134
|
+
logger.error(
|
|
135
|
+
"session_persist_error",
|
|
136
|
+
execution_id=execution_id[:8],
|
|
137
|
+
error=str(e)
|
|
138
|
+
)
|
|
139
|
+
return False
|
|
140
|
+
|
|
141
|
+
def build_conversation_context(
|
|
142
|
+
self,
|
|
143
|
+
session_messages: List[Dict[str, Any]]
|
|
144
|
+
) -> List[Dict[str, str]]:
|
|
145
|
+
"""
|
|
146
|
+
Convert Control Plane session messages to Agno format.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
session_messages: Messages from Control Plane
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
List of dicts with 'role' and 'content' for Agno
|
|
153
|
+
"""
|
|
154
|
+
context = []
|
|
155
|
+
for msg in session_messages:
|
|
156
|
+
context.append({
|
|
157
|
+
"role": msg.get("role", "user"),
|
|
158
|
+
"content": msg.get("content", ""),
|
|
159
|
+
})
|
|
160
|
+
return context
|
|
161
|
+
|
|
162
|
+
def extract_messages_from_result(
|
|
163
|
+
self,
|
|
164
|
+
result: Any,
|
|
165
|
+
user_id: Optional[str] = None
|
|
166
|
+
) -> List[Dict[str, Any]]:
|
|
167
|
+
"""
|
|
168
|
+
Extract messages from Agno Agent/Team result.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
result: Agno RunResponse object
|
|
172
|
+
user_id: Optional user ID to attach
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List of message dicts ready for persistence
|
|
176
|
+
"""
|
|
177
|
+
messages = []
|
|
178
|
+
|
|
179
|
+
if hasattr(result, "messages") and result.messages:
|
|
180
|
+
for msg in result.messages:
|
|
181
|
+
messages.append({
|
|
182
|
+
"role": msg.role,
|
|
183
|
+
"content": msg.content,
|
|
184
|
+
"timestamp": (
|
|
185
|
+
_safe_timestamp_to_iso(msg.created_at)
|
|
186
|
+
if hasattr(msg, "created_at") and msg.created_at is not None
|
|
187
|
+
else datetime.now(timezone.utc).isoformat()
|
|
188
|
+
),
|
|
189
|
+
"user_id": getattr(msg, "user_id", user_id),
|
|
190
|
+
"user_name": getattr(msg, "user_name", None),
|
|
191
|
+
"user_email": getattr(msg, "user_email", None),
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
return messages
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""Skill factory - instantiates skill toolkits from Control Plane configuration"""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Any, List
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import structlog
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
from agno.tools.shell import ShellTools
|
|
9
|
+
from agno.tools.python import PythonTools
|
|
10
|
+
from agno.tools.file import FileTools
|
|
11
|
+
from control_plane_api.worker.services.workflow_executor_tools import WorkflowExecutorTools
|
|
12
|
+
|
|
13
|
+
logger = structlog.get_logger()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SkillFactory:
|
|
17
|
+
"""
|
|
18
|
+
Factory for creating skill toolkit instances from Control Plane skill configurations.
|
|
19
|
+
|
|
20
|
+
Centralizes skill instantiation logic that was previously duplicated
|
|
21
|
+
in agent_activities.py and team_activities.py.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def create_skill(skill_data: dict) -> Optional[Any]:
|
|
26
|
+
"""
|
|
27
|
+
Create a skill toolkit from Control Plane configuration.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
skill_data: Skill config from Control Plane API:
|
|
31
|
+
- type: Skill type (file_system, shell, python, etc.)
|
|
32
|
+
- name: Skill name
|
|
33
|
+
- configuration: Dict with skill-specific config
|
|
34
|
+
- enabled: Whether skill is enabled
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Instantiated skill toolkit or None if disabled/unsupported
|
|
38
|
+
"""
|
|
39
|
+
if not skill_data.get("enabled", True):
|
|
40
|
+
logger.info(
|
|
41
|
+
"skill_skipped_disabled",
|
|
42
|
+
skill_name=skill_data.get("name")
|
|
43
|
+
)
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
skill_type = skill_data.get("type", "").lower()
|
|
47
|
+
config = skill_data.get("configuration", {})
|
|
48
|
+
name = skill_data.get("name", "Unknown")
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
# File system tools
|
|
52
|
+
if skill_type in ["file_system", "file", "file_generation"]:
|
|
53
|
+
base_dir = config.get("base_directory", "/workspace")
|
|
54
|
+
return FileTools(base_dir=Path(base_dir))
|
|
55
|
+
|
|
56
|
+
# Shell/terminal tools
|
|
57
|
+
elif skill_type in ["shell", "terminal", "bash"]:
|
|
58
|
+
return ShellTools()
|
|
59
|
+
|
|
60
|
+
# Python tools
|
|
61
|
+
elif skill_type in ["python", "python_code"]:
|
|
62
|
+
return PythonTools()
|
|
63
|
+
|
|
64
|
+
# Workflow executor tools
|
|
65
|
+
elif skill_type in ["workflow_executor", "workflow"]:
|
|
66
|
+
logger.info(
|
|
67
|
+
"🔍 Creating workflow_executor skill",
|
|
68
|
+
skill_name=name,
|
|
69
|
+
skill_type=skill_type,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# New multi-workflow format
|
|
73
|
+
workflows = config.get("workflows")
|
|
74
|
+
|
|
75
|
+
# Legacy single-workflow format
|
|
76
|
+
workflow_type = config.get("workflow_type", "json")
|
|
77
|
+
workflow_definition = config.get("workflow_definition")
|
|
78
|
+
python_dsl_code = config.get("python_dsl_code")
|
|
79
|
+
|
|
80
|
+
# Common configuration
|
|
81
|
+
validation_enabled = config.get("validation_enabled", True)
|
|
82
|
+
default_runner = config.get("default_runner")
|
|
83
|
+
timeout = config.get("timeout", 3600)
|
|
84
|
+
default_parameters = config.get("default_parameters")
|
|
85
|
+
|
|
86
|
+
# Get Kubiya API credentials from environment
|
|
87
|
+
# These are needed for remote workflow execution
|
|
88
|
+
kubiya_api_key = os.environ.get("KUBIYA_API_KEY")
|
|
89
|
+
kubiya_api_base = os.environ.get("KUBIYA_API_BASE", "https://api.kubiya.ai")
|
|
90
|
+
|
|
91
|
+
logger.info(
|
|
92
|
+
"workflow_executor_config",
|
|
93
|
+
skill_name=name,
|
|
94
|
+
has_workflows=bool(workflows),
|
|
95
|
+
workflows_count=len(workflows) if workflows else 0,
|
|
96
|
+
has_api_key=bool(kubiya_api_key),
|
|
97
|
+
api_base=kubiya_api_base,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if not kubiya_api_key:
|
|
101
|
+
logger.warning(
|
|
102
|
+
"workflow_executor_no_api_key",
|
|
103
|
+
skill_name=name,
|
|
104
|
+
message="KUBIYA_API_KEY not found - workflow execution will fail"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
workflow_tool = WorkflowExecutorTools(
|
|
108
|
+
name=name, # Pass the skill name from configuration
|
|
109
|
+
workflows=workflows,
|
|
110
|
+
workflow_type=workflow_type,
|
|
111
|
+
workflow_definition=workflow_definition,
|
|
112
|
+
python_dsl_code=python_dsl_code,
|
|
113
|
+
validation_enabled=validation_enabled,
|
|
114
|
+
default_runner=default_runner,
|
|
115
|
+
timeout=timeout,
|
|
116
|
+
default_parameters=default_parameters,
|
|
117
|
+
kubiya_api_key=kubiya_api_key, # Explicitly pass API key
|
|
118
|
+
kubiya_api_base=kubiya_api_base, # Explicitly pass API base URL
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
logger.info(
|
|
122
|
+
"✅ Workflow executor skill created successfully",
|
|
123
|
+
skill_name=name,
|
|
124
|
+
tool_class=type(workflow_tool).__name__,
|
|
125
|
+
has_functions=hasattr(workflow_tool, 'functions'),
|
|
126
|
+
function_count=len(workflow_tool.functions) if hasattr(workflow_tool, 'functions') else 0,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
return workflow_tool
|
|
130
|
+
|
|
131
|
+
else:
|
|
132
|
+
logger.warning(
|
|
133
|
+
"skill_type_not_supported",
|
|
134
|
+
skill_type=skill_type,
|
|
135
|
+
skill_name=name
|
|
136
|
+
)
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logger.error(
|
|
141
|
+
"skill_instantiation_failed",
|
|
142
|
+
skill_type=skill_type,
|
|
143
|
+
skill_name=name,
|
|
144
|
+
error=str(e)
|
|
145
|
+
)
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
@classmethod
|
|
149
|
+
def create_skills_from_list(
|
|
150
|
+
cls,
|
|
151
|
+
skill_configs: List[dict]
|
|
152
|
+
) -> List[Any]:
|
|
153
|
+
"""
|
|
154
|
+
Create multiple skills from a list of configurations.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
skill_configs: List of skill config dicts
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
List of instantiated skills (non-None)
|
|
161
|
+
"""
|
|
162
|
+
skills = []
|
|
163
|
+
|
|
164
|
+
for config in skill_configs:
|
|
165
|
+
skill = cls.create_skill(config)
|
|
166
|
+
if skill:
|
|
167
|
+
skills.append(skill)
|
|
168
|
+
|
|
169
|
+
logger.info(
|
|
170
|
+
"skills_created",
|
|
171
|
+
requested_count=len(skill_configs),
|
|
172
|
+
created_count=len(skills)
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return skills
|