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,379 @@
|
|
|
1
|
+
"""Agent-related Temporal activities"""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from temporalio import activity
|
|
7
|
+
import structlog
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
from control_plane_api.app.lib.supabase import get_supabase
|
|
11
|
+
from control_plane_api.app.services.litellm_service import litellm_service
|
|
12
|
+
from control_plane_api.app.services.agno_service import agno_service
|
|
13
|
+
|
|
14
|
+
logger = structlog.get_logger()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ActivityExecuteAgentInput:
|
|
19
|
+
"""Input for execute_agent_llm activity"""
|
|
20
|
+
execution_id: str
|
|
21
|
+
agent_id: str
|
|
22
|
+
organization_id: str
|
|
23
|
+
prompt: str
|
|
24
|
+
system_prompt: Optional[str] = None
|
|
25
|
+
model_id: Optional[str] = None
|
|
26
|
+
model_config: dict = None
|
|
27
|
+
mcp_servers: dict = None # MCP servers configuration
|
|
28
|
+
session_id: Optional[str] = None # Session ID for Agno session management (use execution_id)
|
|
29
|
+
user_id: Optional[str] = None # User ID for multi-user support
|
|
30
|
+
control_plane_url: Optional[str] = None # Control Plane URL for fetching skills
|
|
31
|
+
api_key: Optional[str] = None # API key for authentication
|
|
32
|
+
|
|
33
|
+
def __post_init__(self):
|
|
34
|
+
if self.model_config is None:
|
|
35
|
+
self.model_config = {}
|
|
36
|
+
if self.mcp_servers is None:
|
|
37
|
+
self.mcp_servers = {}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class ActivityUpdateExecutionInput:
|
|
42
|
+
"""Input for update_execution_status activity"""
|
|
43
|
+
execution_id: str
|
|
44
|
+
status: str
|
|
45
|
+
started_at: Optional[str] = None
|
|
46
|
+
completed_at: Optional[str] = None
|
|
47
|
+
response: Optional[str] = None
|
|
48
|
+
error_message: Optional[str] = None
|
|
49
|
+
usage: dict = None
|
|
50
|
+
execution_metadata: dict = None
|
|
51
|
+
|
|
52
|
+
def __post_init__(self):
|
|
53
|
+
if self.usage is None:
|
|
54
|
+
self.usage = {}
|
|
55
|
+
if self.execution_metadata is None:
|
|
56
|
+
self.execution_metadata = {}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class ActivityUpdateAgentInput:
|
|
61
|
+
"""Input for update_agent_status activity"""
|
|
62
|
+
agent_id: str
|
|
63
|
+
organization_id: str
|
|
64
|
+
status: str
|
|
65
|
+
last_active_at: str
|
|
66
|
+
error_message: Optional[str] = None
|
|
67
|
+
state: dict = None
|
|
68
|
+
|
|
69
|
+
def __post_init__(self):
|
|
70
|
+
if self.state is None:
|
|
71
|
+
self.state = {}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@activity.defn
|
|
75
|
+
async def execute_agent_llm(input: ActivityExecuteAgentInput) -> dict:
|
|
76
|
+
"""
|
|
77
|
+
Execute an agent's LLM call with Agno Teams and session management.
|
|
78
|
+
|
|
79
|
+
This activity uses Agno Teams with session support for persistent conversation history.
|
|
80
|
+
The session_id should be set to execution_id for 1:1 mapping.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
input: Activity input with execution details
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Dict with response, usage, success flag, session messages, etc.
|
|
87
|
+
"""
|
|
88
|
+
activity.logger.info(
|
|
89
|
+
f"Executing agent LLM call with Agno Sessions",
|
|
90
|
+
extra={
|
|
91
|
+
"execution_id": input.execution_id,
|
|
92
|
+
"agent_id": input.agent_id,
|
|
93
|
+
"model_id": input.model_id,
|
|
94
|
+
"has_mcp_servers": bool(input.mcp_servers),
|
|
95
|
+
"session_id": input.session_id,
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
# Get model from input or use default
|
|
101
|
+
model = input.model_id or os.environ.get("LITELLM_DEFAULT_MODEL", "kubiya/claude-sonnet-4")
|
|
102
|
+
|
|
103
|
+
# Fetch resolved skills from Control Plane if available
|
|
104
|
+
skills = []
|
|
105
|
+
if input.control_plane_url and input.api_key and input.agent_id:
|
|
106
|
+
import httpx
|
|
107
|
+
try:
|
|
108
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
109
|
+
response = await client.get(
|
|
110
|
+
f"{input.control_plane_url}/api/v1/skills/associations/agents/{input.agent_id}/skills/resolved",
|
|
111
|
+
headers={"Authorization": f"Bearer {input.api_key}"}
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if response.status_code == 200:
|
|
115
|
+
skills = response.json()
|
|
116
|
+
activity.logger.info(
|
|
117
|
+
f"Resolved skills from Control Plane",
|
|
118
|
+
extra={
|
|
119
|
+
"agent_id": input.agent_id,
|
|
120
|
+
"skill_count": len(skills),
|
|
121
|
+
"skill_types": [t.get("type") for t in skills],
|
|
122
|
+
"skill_sources": [t.get("source") for t in skills]
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
activity.logger.warning(
|
|
127
|
+
f"Failed to fetch skills from Control Plane: {response.status_code}",
|
|
128
|
+
extra={
|
|
129
|
+
"status_code": response.status_code,
|
|
130
|
+
"response_text": response.text[:500]
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
except Exception as e:
|
|
134
|
+
activity.logger.error(
|
|
135
|
+
f"Error fetching skills from Control Plane: {str(e)}",
|
|
136
|
+
extra={"error": str(e)}
|
|
137
|
+
)
|
|
138
|
+
# Continue execution without skills
|
|
139
|
+
|
|
140
|
+
# Use Agno Teams with session management
|
|
141
|
+
activity.logger.info(
|
|
142
|
+
f"Using Agno Teams with sessions and skills",
|
|
143
|
+
extra={
|
|
144
|
+
"execution_id": input.execution_id,
|
|
145
|
+
"session_id": input.session_id,
|
|
146
|
+
"has_mcp_servers": bool(input.mcp_servers),
|
|
147
|
+
"mcp_servers": list(input.mcp_servers.keys()) if input.mcp_servers else [],
|
|
148
|
+
"skill_count": len(skills),
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Execute with session support and streaming - Agno handles conversation history automatically
|
|
153
|
+
result = await agno_service.execute_agent_async(
|
|
154
|
+
prompt=input.prompt,
|
|
155
|
+
model=model,
|
|
156
|
+
system_prompt=input.system_prompt,
|
|
157
|
+
mcp_servers=input.mcp_servers,
|
|
158
|
+
skills=skills, # Pass resolved skills
|
|
159
|
+
session_id=input.session_id, # Pass session_id for persistence
|
|
160
|
+
user_id=input.user_id, # Pass user_id for multi-user support
|
|
161
|
+
stream=True, # Enable real-time streaming for UI updates
|
|
162
|
+
**(input.model_config or {})
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
activity.logger.info(
|
|
166
|
+
f"Agent LLM call completed",
|
|
167
|
+
extra={
|
|
168
|
+
"execution_id": input.execution_id,
|
|
169
|
+
"success": result.get("success"),
|
|
170
|
+
"model": result.get("model"),
|
|
171
|
+
"mcp_tools_used": result.get("mcp_tools_used", 0),
|
|
172
|
+
"session_messages": len(result.get("messages", [])),
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return result
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
activity.logger.error(
|
|
180
|
+
f"Agent LLM call failed",
|
|
181
|
+
extra={
|
|
182
|
+
"execution_id": input.execution_id,
|
|
183
|
+
"error": str(e),
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
return {
|
|
187
|
+
"success": False,
|
|
188
|
+
"error": str(e),
|
|
189
|
+
"model": input.model_id,
|
|
190
|
+
"usage": None,
|
|
191
|
+
"finish_reason": "error",
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@activity.defn
|
|
196
|
+
async def update_execution_status(input: ActivityUpdateExecutionInput) -> dict:
|
|
197
|
+
"""
|
|
198
|
+
Update execution status in database.
|
|
199
|
+
|
|
200
|
+
This activity updates the execution record with status, results, timestamps, etc.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
input: Activity input with update details
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Dict with success flag
|
|
207
|
+
"""
|
|
208
|
+
activity.logger.info(
|
|
209
|
+
f"Updating execution status",
|
|
210
|
+
extra={
|
|
211
|
+
"execution_id": input.execution_id,
|
|
212
|
+
"status": input.status,
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
# Get Control Plane URL and API key from environment (set by worker)
|
|
217
|
+
import os
|
|
218
|
+
import httpx
|
|
219
|
+
|
|
220
|
+
control_plane_url = os.getenv("CONTROL_PLANE_URL")
|
|
221
|
+
kubiya_api_key = os.getenv("KUBIYA_API_KEY")
|
|
222
|
+
|
|
223
|
+
if not control_plane_url:
|
|
224
|
+
raise ValueError("CONTROL_PLANE_URL environment variable not set")
|
|
225
|
+
if not kubiya_api_key:
|
|
226
|
+
raise ValueError("KUBIYA_API_KEY environment variable not set")
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
# Build update payload
|
|
230
|
+
update_payload = {}
|
|
231
|
+
|
|
232
|
+
if input.status:
|
|
233
|
+
update_payload["status"] = input.status
|
|
234
|
+
|
|
235
|
+
if input.started_at:
|
|
236
|
+
update_payload["started_at"] = input.started_at
|
|
237
|
+
|
|
238
|
+
if input.completed_at:
|
|
239
|
+
update_payload["completed_at"] = input.completed_at
|
|
240
|
+
|
|
241
|
+
if input.response is not None:
|
|
242
|
+
update_payload["response"] = input.response
|
|
243
|
+
|
|
244
|
+
if input.error_message is not None:
|
|
245
|
+
update_payload["error_message"] = input.error_message
|
|
246
|
+
|
|
247
|
+
if input.usage:
|
|
248
|
+
update_payload["usage"] = input.usage
|
|
249
|
+
|
|
250
|
+
if input.execution_metadata:
|
|
251
|
+
update_payload["execution_metadata"] = input.execution_metadata
|
|
252
|
+
|
|
253
|
+
# Call Control Plane API
|
|
254
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
255
|
+
response = await client.patch(
|
|
256
|
+
f"{control_plane_url}/api/v1/executions/{input.execution_id}",
|
|
257
|
+
json=update_payload,
|
|
258
|
+
headers={
|
|
259
|
+
"Authorization": f"Bearer {kubiya_api_key}",
|
|
260
|
+
"Content-Type": "application/json",
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
if response.status_code == 404:
|
|
265
|
+
raise Exception(f"Execution not found: {input.execution_id}")
|
|
266
|
+
elif response.status_code != 200:
|
|
267
|
+
raise Exception(f"Failed to update execution: {response.status_code} - {response.text}")
|
|
268
|
+
|
|
269
|
+
activity.logger.info(
|
|
270
|
+
f"Execution status updated",
|
|
271
|
+
extra={
|
|
272
|
+
"execution_id": input.execution_id,
|
|
273
|
+
"status": input.status,
|
|
274
|
+
}
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return {"success": True}
|
|
278
|
+
|
|
279
|
+
except Exception as e:
|
|
280
|
+
activity.logger.error(
|
|
281
|
+
f"Failed to update execution status",
|
|
282
|
+
extra={
|
|
283
|
+
"execution_id": input.execution_id,
|
|
284
|
+
"error": str(e),
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
raise
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
@activity.defn
|
|
291
|
+
async def update_agent_status(input: ActivityUpdateAgentInput) -> dict:
|
|
292
|
+
"""
|
|
293
|
+
Update agent status in database.
|
|
294
|
+
|
|
295
|
+
This activity updates the agent record with status, error messages, etc.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
input: Activity input with update details
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
Dict with success flag
|
|
302
|
+
"""
|
|
303
|
+
activity.logger.info(
|
|
304
|
+
f"Updating agent status",
|
|
305
|
+
extra={
|
|
306
|
+
"agent_id": input.agent_id,
|
|
307
|
+
"status": input.status,
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# Get Control Plane URL and API key from environment (set by worker)
|
|
312
|
+
import os
|
|
313
|
+
import httpx
|
|
314
|
+
|
|
315
|
+
control_plane_url = os.getenv("CONTROL_PLANE_URL")
|
|
316
|
+
kubiya_api_key = os.getenv("KUBIYA_API_KEY")
|
|
317
|
+
|
|
318
|
+
if not control_plane_url:
|
|
319
|
+
raise ValueError("CONTROL_PLANE_URL environment variable not set")
|
|
320
|
+
if not kubiya_api_key:
|
|
321
|
+
raise ValueError("KUBIYA_API_KEY environment variable not set")
|
|
322
|
+
|
|
323
|
+
try:
|
|
324
|
+
# Build update payload
|
|
325
|
+
update_payload = {
|
|
326
|
+
"status": input.status,
|
|
327
|
+
"last_active_at": input.last_active_at,
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if input.error_message is not None:
|
|
331
|
+
update_payload["error_message"] = input.error_message
|
|
332
|
+
|
|
333
|
+
if input.state:
|
|
334
|
+
update_payload["state"] = input.state
|
|
335
|
+
|
|
336
|
+
# Call Control Plane API
|
|
337
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
338
|
+
response = await client.patch(
|
|
339
|
+
f"{control_plane_url}/api/v1/agents/{input.agent_id}",
|
|
340
|
+
json=update_payload,
|
|
341
|
+
headers={
|
|
342
|
+
"Authorization": f"Bearer {kubiya_api_key}",
|
|
343
|
+
"Content-Type": "application/json",
|
|
344
|
+
}
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# For team executions, the "agent_id" is actually a team_id, so it won't be found in agents table
|
|
348
|
+
# This is expected and not an error - just log and return success
|
|
349
|
+
if response.status_code == 404:
|
|
350
|
+
activity.logger.info(
|
|
351
|
+
f"Agent not found (likely a team execution) - skipping agent status update",
|
|
352
|
+
extra={
|
|
353
|
+
"agent_id": input.agent_id,
|
|
354
|
+
"status": input.status,
|
|
355
|
+
}
|
|
356
|
+
)
|
|
357
|
+
return {"success": True, "skipped": True}
|
|
358
|
+
elif response.status_code != 200:
|
|
359
|
+
raise Exception(f"Failed to update agent: {response.status_code} - {response.text}")
|
|
360
|
+
|
|
361
|
+
activity.logger.info(
|
|
362
|
+
f"Agent status updated",
|
|
363
|
+
extra={
|
|
364
|
+
"agent_id": input.agent_id,
|
|
365
|
+
"status": input.status,
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
return {"success": True}
|
|
370
|
+
|
|
371
|
+
except Exception as e:
|
|
372
|
+
activity.logger.error(
|
|
373
|
+
f"Failed to update agent status",
|
|
374
|
+
extra={
|
|
375
|
+
"agent_id": input.agent_id,
|
|
376
|
+
"error": str(e),
|
|
377
|
+
}
|
|
378
|
+
)
|
|
379
|
+
raise
|