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.

Files changed (185) hide show
  1. control_plane_api/README.md +266 -0
  2. control_plane_api/__init__.py +0 -0
  3. control_plane_api/__version__.py +1 -0
  4. control_plane_api/alembic/README +1 -0
  5. control_plane_api/alembic/env.py +98 -0
  6. control_plane_api/alembic/script.py.mako +28 -0
  7. control_plane_api/alembic/versions/1382bec74309_initial_migration_with_all_models.py +251 -0
  8. control_plane_api/alembic/versions/1f54bc2a37e3_add_analytics_tables.py +162 -0
  9. control_plane_api/alembic/versions/2e4cb136dc10_rename_toolset_ids_to_skill_ids_in_teams.py +30 -0
  10. control_plane_api/alembic/versions/31cd69a644ce_add_skill_templates_table.py +28 -0
  11. control_plane_api/alembic/versions/89e127caa47d_add_jobs_and_job_executions_tables.py +161 -0
  12. control_plane_api/alembic/versions/add_llm_models_table.py +51 -0
  13. control_plane_api/alembic/versions/b0e10697f212_add_runtime_column_to_teams_simple.py +42 -0
  14. control_plane_api/alembic/versions/ce43b24b63bf_add_execution_trigger_source_and_fix_.py +155 -0
  15. control_plane_api/alembic/versions/d4eaf16e3f8d_rename_toolsets_to_skills.py +84 -0
  16. control_plane_api/alembic/versions/efa2dc427da1_rename_metadata_to_custom_metadata.py +32 -0
  17. control_plane_api/alembic/versions/f973b431d1ce_add_workflow_executor_to_skill_types.py +44 -0
  18. control_plane_api/alembic.ini +148 -0
  19. control_plane_api/api/index.py +12 -0
  20. control_plane_api/app/__init__.py +11 -0
  21. control_plane_api/app/activities/__init__.py +20 -0
  22. control_plane_api/app/activities/agent_activities.py +379 -0
  23. control_plane_api/app/activities/team_activities.py +410 -0
  24. control_plane_api/app/activities/temporal_cloud_activities.py +577 -0
  25. control_plane_api/app/config/__init__.py +35 -0
  26. control_plane_api/app/config/api_config.py +354 -0
  27. control_plane_api/app/config/model_pricing.py +318 -0
  28. control_plane_api/app/config.py +95 -0
  29. control_plane_api/app/database.py +135 -0
  30. control_plane_api/app/exceptions.py +408 -0
  31. control_plane_api/app/lib/__init__.py +11 -0
  32. control_plane_api/app/lib/job_executor.py +312 -0
  33. control_plane_api/app/lib/kubiya_client.py +235 -0
  34. control_plane_api/app/lib/litellm_pricing.py +166 -0
  35. control_plane_api/app/lib/planning_tools/__init__.py +22 -0
  36. control_plane_api/app/lib/planning_tools/agents.py +155 -0
  37. control_plane_api/app/lib/planning_tools/base.py +189 -0
  38. control_plane_api/app/lib/planning_tools/environments.py +214 -0
  39. control_plane_api/app/lib/planning_tools/resources.py +240 -0
  40. control_plane_api/app/lib/planning_tools/teams.py +198 -0
  41. control_plane_api/app/lib/policy_enforcer_client.py +939 -0
  42. control_plane_api/app/lib/redis_client.py +436 -0
  43. control_plane_api/app/lib/supabase.py +71 -0
  44. control_plane_api/app/lib/temporal_client.py +138 -0
  45. control_plane_api/app/lib/validation/__init__.py +20 -0
  46. control_plane_api/app/lib/validation/runtime_validation.py +287 -0
  47. control_plane_api/app/main.py +128 -0
  48. control_plane_api/app/middleware/__init__.py +8 -0
  49. control_plane_api/app/middleware/auth.py +513 -0
  50. control_plane_api/app/middleware/exception_handler.py +267 -0
  51. control_plane_api/app/middleware/rate_limiting.py +384 -0
  52. control_plane_api/app/middleware/request_id.py +202 -0
  53. control_plane_api/app/models/__init__.py +27 -0
  54. control_plane_api/app/models/agent.py +79 -0
  55. control_plane_api/app/models/analytics.py +206 -0
  56. control_plane_api/app/models/associations.py +81 -0
  57. control_plane_api/app/models/environment.py +63 -0
  58. control_plane_api/app/models/execution.py +93 -0
  59. control_plane_api/app/models/job.py +179 -0
  60. control_plane_api/app/models/llm_model.py +75 -0
  61. control_plane_api/app/models/presence.py +49 -0
  62. control_plane_api/app/models/project.py +47 -0
  63. control_plane_api/app/models/session.py +38 -0
  64. control_plane_api/app/models/team.py +66 -0
  65. control_plane_api/app/models/workflow.py +55 -0
  66. control_plane_api/app/policies/README.md +121 -0
  67. control_plane_api/app/policies/approved_users.rego +62 -0
  68. control_plane_api/app/policies/business_hours.rego +51 -0
  69. control_plane_api/app/policies/rate_limiting.rego +100 -0
  70. control_plane_api/app/policies/tool_restrictions.rego +86 -0
  71. control_plane_api/app/routers/__init__.py +4 -0
  72. control_plane_api/app/routers/agents.py +364 -0
  73. control_plane_api/app/routers/agents_v2.py +1260 -0
  74. control_plane_api/app/routers/analytics.py +1014 -0
  75. control_plane_api/app/routers/context_manager.py +562 -0
  76. control_plane_api/app/routers/environment_context.py +270 -0
  77. control_plane_api/app/routers/environments.py +715 -0
  78. control_plane_api/app/routers/execution_environment.py +517 -0
  79. control_plane_api/app/routers/executions.py +1911 -0
  80. control_plane_api/app/routers/health.py +92 -0
  81. control_plane_api/app/routers/health_v2.py +326 -0
  82. control_plane_api/app/routers/integrations.py +274 -0
  83. control_plane_api/app/routers/jobs.py +1344 -0
  84. control_plane_api/app/routers/models.py +82 -0
  85. control_plane_api/app/routers/models_v2.py +361 -0
  86. control_plane_api/app/routers/policies.py +639 -0
  87. control_plane_api/app/routers/presence.py +234 -0
  88. control_plane_api/app/routers/projects.py +902 -0
  89. control_plane_api/app/routers/runners.py +379 -0
  90. control_plane_api/app/routers/runtimes.py +172 -0
  91. control_plane_api/app/routers/secrets.py +155 -0
  92. control_plane_api/app/routers/skills.py +1001 -0
  93. control_plane_api/app/routers/skills_definitions.py +140 -0
  94. control_plane_api/app/routers/task_planning.py +1256 -0
  95. control_plane_api/app/routers/task_queues.py +654 -0
  96. control_plane_api/app/routers/team_context.py +270 -0
  97. control_plane_api/app/routers/teams.py +1400 -0
  98. control_plane_api/app/routers/worker_queues.py +1545 -0
  99. control_plane_api/app/routers/workers.py +935 -0
  100. control_plane_api/app/routers/workflows.py +204 -0
  101. control_plane_api/app/runtimes/__init__.py +6 -0
  102. control_plane_api/app/runtimes/validation.py +344 -0
  103. control_plane_api/app/schemas/job_schemas.py +295 -0
  104. control_plane_api/app/services/__init__.py +1 -0
  105. control_plane_api/app/services/agno_service.py +619 -0
  106. control_plane_api/app/services/litellm_service.py +190 -0
  107. control_plane_api/app/services/policy_service.py +525 -0
  108. control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
  109. control_plane_api/app/skills/__init__.py +44 -0
  110. control_plane_api/app/skills/base.py +229 -0
  111. control_plane_api/app/skills/business_intelligence.py +189 -0
  112. control_plane_api/app/skills/data_visualization.py +154 -0
  113. control_plane_api/app/skills/docker.py +104 -0
  114. control_plane_api/app/skills/file_generation.py +94 -0
  115. control_plane_api/app/skills/file_system.py +110 -0
  116. control_plane_api/app/skills/python.py +92 -0
  117. control_plane_api/app/skills/registry.py +65 -0
  118. control_plane_api/app/skills/shell.py +102 -0
  119. control_plane_api/app/skills/workflow_executor.py +469 -0
  120. control_plane_api/app/utils/workflow_executor.py +354 -0
  121. control_plane_api/app/workflows/__init__.py +11 -0
  122. control_plane_api/app/workflows/agent_execution.py +507 -0
  123. control_plane_api/app/workflows/agent_execution_with_skills.py +222 -0
  124. control_plane_api/app/workflows/namespace_provisioning.py +326 -0
  125. control_plane_api/app/workflows/team_execution.py +399 -0
  126. control_plane_api/scripts/seed_models.py +239 -0
  127. control_plane_api/worker/__init__.py +0 -0
  128. control_plane_api/worker/activities/__init__.py +0 -0
  129. control_plane_api/worker/activities/agent_activities.py +1241 -0
  130. control_plane_api/worker/activities/approval_activities.py +234 -0
  131. control_plane_api/worker/activities/runtime_activities.py +388 -0
  132. control_plane_api/worker/activities/skill_activities.py +267 -0
  133. control_plane_api/worker/activities/team_activities.py +1217 -0
  134. control_plane_api/worker/config/__init__.py +31 -0
  135. control_plane_api/worker/config/worker_config.py +275 -0
  136. control_plane_api/worker/control_plane_client.py +529 -0
  137. control_plane_api/worker/examples/analytics_integration_example.py +362 -0
  138. control_plane_api/worker/models/__init__.py +1 -0
  139. control_plane_api/worker/models/inputs.py +89 -0
  140. control_plane_api/worker/runtimes/__init__.py +31 -0
  141. control_plane_api/worker/runtimes/base.py +789 -0
  142. control_plane_api/worker/runtimes/claude_code_runtime.py +1443 -0
  143. control_plane_api/worker/runtimes/default_runtime.py +617 -0
  144. control_plane_api/worker/runtimes/factory.py +173 -0
  145. control_plane_api/worker/runtimes/validation.py +93 -0
  146. control_plane_api/worker/services/__init__.py +1 -0
  147. control_plane_api/worker/services/agent_executor.py +422 -0
  148. control_plane_api/worker/services/agent_executor_v2.py +383 -0
  149. control_plane_api/worker/services/analytics_collector.py +457 -0
  150. control_plane_api/worker/services/analytics_service.py +464 -0
  151. control_plane_api/worker/services/approval_tools.py +310 -0
  152. control_plane_api/worker/services/approval_tools_agno.py +207 -0
  153. control_plane_api/worker/services/cancellation_manager.py +177 -0
  154. control_plane_api/worker/services/data_visualization.py +827 -0
  155. control_plane_api/worker/services/jira_tools.py +257 -0
  156. control_plane_api/worker/services/runtime_analytics.py +328 -0
  157. control_plane_api/worker/services/session_service.py +194 -0
  158. control_plane_api/worker/services/skill_factory.py +175 -0
  159. control_plane_api/worker/services/team_executor.py +574 -0
  160. control_plane_api/worker/services/team_executor_v2.py +465 -0
  161. control_plane_api/worker/services/workflow_executor_tools.py +1418 -0
  162. control_plane_api/worker/tests/__init__.py +1 -0
  163. control_plane_api/worker/tests/e2e/__init__.py +0 -0
  164. control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
  165. control_plane_api/worker/tests/integration/__init__.py +0 -0
  166. control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
  167. control_plane_api/worker/tests/unit/__init__.py +0 -0
  168. control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
  169. control_plane_api/worker/utils/__init__.py +1 -0
  170. control_plane_api/worker/utils/chunk_batcher.py +305 -0
  171. control_plane_api/worker/utils/retry_utils.py +60 -0
  172. control_plane_api/worker/utils/streaming_utils.py +373 -0
  173. control_plane_api/worker/worker.py +753 -0
  174. control_plane_api/worker/workflows/__init__.py +0 -0
  175. control_plane_api/worker/workflows/agent_execution.py +589 -0
  176. control_plane_api/worker/workflows/team_execution.py +429 -0
  177. kubiya_control_plane_api-0.3.4.dist-info/METADATA +229 -0
  178. kubiya_control_plane_api-0.3.4.dist-info/RECORD +182 -0
  179. kubiya_control_plane_api-0.3.4.dist-info/entry_points.txt +2 -0
  180. kubiya_control_plane_api-0.3.4.dist-info/top_level.txt +1 -0
  181. kubiya_control_plane_api-0.1.0.dist-info/METADATA +0 -66
  182. kubiya_control_plane_api-0.1.0.dist-info/RECORD +0 -5
  183. kubiya_control_plane_api-0.1.0.dist-info/top_level.txt +0 -1
  184. {kubiya_control_plane_api-0.1.0.dist-info/licenses → control_plane_api}/LICENSE +0 -0
  185. {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