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,308 @@
1
+ """Integration tests for Control Plane client integration with activities"""
2
+
3
+ import pytest
4
+ import os
5
+ from unittest.mock import Mock, patch, MagicMock
6
+ from pathlib import Path
7
+ import sys
8
+
9
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent))
10
+
11
+ from control_plane_api.worker.control_plane_client import ControlPlaneClient, get_control_plane_client
12
+
13
+
14
+ class TestControlPlaneIntegration:
15
+ """Test integration between Control Plane client and activity modules"""
16
+
17
+ @pytest.fixture
18
+ def mock_http_server(self):
19
+ """Mock HTTP responses from Control Plane"""
20
+ with patch('control_plane_client.httpx.Client') as mock_client_class:
21
+ mock_client = MagicMock()
22
+ mock_client_class.return_value = mock_client
23
+ yield mock_client
24
+
25
+ def test_client_can_publish_events(self, mock_http_server):
26
+ """Test that client can successfully publish events to Control Plane"""
27
+ client = ControlPlaneClient(
28
+ base_url="http://localhost:8000",
29
+ api_key="test_key"
30
+ )
31
+
32
+ # Mock successful response
33
+ mock_response = Mock()
34
+ mock_response.status_code = 200
35
+ mock_http_server.post = Mock(return_value=mock_response)
36
+
37
+ # Publish event
38
+ result = client.publish_event(
39
+ execution_id="exec_123",
40
+ event_type="message_chunk",
41
+ data={"content": "test"}
42
+ )
43
+
44
+ assert result is True
45
+ assert mock_http_server.post.called
46
+
47
+ def test_client_can_cache_metadata(self, mock_http_server):
48
+ """Test that client can cache execution metadata"""
49
+ client = ControlPlaneClient(
50
+ base_url="http://localhost:8000",
51
+ api_key="test_key"
52
+ )
53
+
54
+ # Mock successful response
55
+ mock_response = Mock()
56
+ mock_response.status_code = 202
57
+ mock_http_server.post = Mock(return_value=mock_response)
58
+
59
+ # Cache metadata
60
+ result = client.cache_metadata(
61
+ execution_id="exec_123",
62
+ execution_type="AGENT"
63
+ )
64
+
65
+ assert result is True
66
+
67
+ def test_client_can_persist_session(self, mock_http_server):
68
+ """Test that client can persist session history"""
69
+ client = ControlPlaneClient(
70
+ base_url="http://localhost:8000",
71
+ api_key="test_key"
72
+ )
73
+
74
+ # Mock successful response
75
+ mock_response = Mock()
76
+ mock_response.status_code = 201
77
+ mock_http_server.post = Mock(return_value=mock_response)
78
+
79
+ # Persist session
80
+ messages = [
81
+ {"role": "user", "content": "Hello"},
82
+ {"role": "assistant", "content": "Hi!"}
83
+ ]
84
+
85
+ result = client.persist_session(
86
+ execution_id="exec_123",
87
+ session_id="session_456",
88
+ user_id="user_789",
89
+ messages=messages
90
+ )
91
+
92
+ assert result is True
93
+
94
+ def test_client_can_fetch_skills(self, mock_http_server):
95
+ """Test that client can fetch skills from Control Plane"""
96
+ client = ControlPlaneClient(
97
+ base_url="http://localhost:8000",
98
+ api_key="test_key"
99
+ )
100
+
101
+ # Mock successful response with skills
102
+ mock_response = Mock()
103
+ mock_response.status_code = 200
104
+ mock_response.json = Mock(return_value=[
105
+ {"type": "file_system", "name": "File Tools", "enabled": True},
106
+ {"type": "shell", "name": "Shell Tools", "enabled": True}
107
+ ])
108
+ mock_http_server.get = Mock(return_value=mock_response)
109
+
110
+ # Fetch skills
111
+ skills = client.get_skills(agent_id="agent_123")
112
+
113
+ assert len(skills) == 2
114
+ assert skills[0]["type"] == "file_system"
115
+
116
+ def test_client_handles_connection_errors_gracefully(self, mock_http_server):
117
+ """Test that client handles connection errors without crashing"""
118
+ client = ControlPlaneClient(
119
+ base_url="http://localhost:8000",
120
+ api_key="test_key"
121
+ )
122
+
123
+ # Mock connection error
124
+ import httpx
125
+ mock_http_server.post = Mock(side_effect=httpx.ConnectError("Connection failed"))
126
+
127
+ # Should not raise exception
128
+ result = client.publish_event(
129
+ execution_id="exec_123",
130
+ event_type="message_chunk",
131
+ data={"content": "test"}
132
+ )
133
+
134
+ assert result is False
135
+
136
+ def test_client_handles_timeout_errors_gracefully(self, mock_http_server):
137
+ """Test that client handles timeout errors without crashing"""
138
+ client = ControlPlaneClient(
139
+ base_url="http://localhost:8000",
140
+ api_key="test_key"
141
+ )
142
+
143
+ # Mock timeout error
144
+ import httpx
145
+ mock_http_server.post = Mock(side_effect=httpx.TimeoutException("Timeout"))
146
+
147
+ # Should not raise exception
148
+ result = client.publish_event(
149
+ execution_id="exec_123",
150
+ event_type="message_chunk",
151
+ data={"content": "test"}
152
+ )
153
+
154
+ assert result is False
155
+
156
+ def test_singleton_integration_with_environment(self):
157
+ """Test that singleton pattern works with environment variables"""
158
+ # Reset singleton
159
+ import control_plane_client
160
+ control_plane_client._control_plane_client = None
161
+
162
+ with patch.dict(os.environ, {
163
+ 'CONTROL_PLANE_URL': 'http://test.example.com',
164
+ 'KUBIYA_API_KEY': 'integration_test_key'
165
+ }):
166
+ client1 = get_control_plane_client()
167
+ client2 = get_control_plane_client()
168
+
169
+ # Should return same instance
170
+ assert client1 is client2
171
+ assert client1.base_url == "http://test.example.com"
172
+ assert client1.api_key == "integration_test_key"
173
+
174
+ # Reset for other tests
175
+ control_plane_client._control_plane_client = None
176
+
177
+ def test_multiple_events_can_be_published_sequentially(self, mock_http_server):
178
+ """Test publishing multiple events in sequence"""
179
+ client = ControlPlaneClient(
180
+ base_url="http://localhost:8000",
181
+ api_key="test_key"
182
+ )
183
+
184
+ # Mock successful responses
185
+ mock_response = Mock()
186
+ mock_response.status_code = 200
187
+ mock_http_server.post = Mock(return_value=mock_response)
188
+
189
+ # Publish multiple events
190
+ results = []
191
+ for i in range(5):
192
+ result = client.publish_event(
193
+ execution_id=f"exec_{i}",
194
+ event_type="message_chunk",
195
+ data={"content": f"chunk {i}"}
196
+ )
197
+ results.append(result)
198
+
199
+ # All should succeed
200
+ assert all(results)
201
+ assert mock_http_server.post.call_count == 5
202
+
203
+ def test_client_properly_formats_urls(self, mock_http_server):
204
+ """Test that client formats URLs correctly"""
205
+ client = ControlPlaneClient(
206
+ base_url="http://localhost:8000",
207
+ api_key="test_key"
208
+ )
209
+
210
+ mock_response = Mock()
211
+ mock_response.status_code = 200
212
+ mock_http_server.post = Mock(return_value=mock_response)
213
+
214
+ # Publish event
215
+ client.publish_event(
216
+ execution_id="exec_123",
217
+ event_type="test",
218
+ data={}
219
+ )
220
+
221
+ # Check URL was properly formatted
222
+ call_args = mock_http_server.post.call_args
223
+ url = call_args[0][0]
224
+ assert url == "http://localhost:8000/api/v1/executions/exec_123/events"
225
+
226
+ def test_client_includes_proper_headers(self, mock_http_server):
227
+ """Test that client includes proper authentication headers"""
228
+ client = ControlPlaneClient(
229
+ base_url="http://localhost:8000",
230
+ api_key="secret_key_123"
231
+ )
232
+
233
+ mock_response = Mock()
234
+ mock_response.status_code = 200
235
+ mock_http_server.post = Mock(return_value=mock_response)
236
+
237
+ # Publish event
238
+ client.publish_event(
239
+ execution_id="exec_123",
240
+ event_type="test",
241
+ data={}
242
+ )
243
+
244
+ # Check headers
245
+ call_args = mock_http_server.post.call_args
246
+ headers = call_args[1]["headers"]
247
+ assert headers["Authorization"] == "UserKey secret_key_123"
248
+
249
+ def test_session_persistence_includes_all_fields(self, mock_http_server):
250
+ """Test that session persistence sends all required fields"""
251
+ client = ControlPlaneClient(
252
+ base_url="http://localhost:8000",
253
+ api_key="test_key"
254
+ )
255
+
256
+ mock_response = Mock()
257
+ mock_response.status_code = 201
258
+ mock_http_server.post = Mock(return_value=mock_response)
259
+
260
+ # Persist session with all fields
261
+ messages = [{"role": "user", "content": "test"}]
262
+ metadata = {"team_id": "team_123", "turn": 1}
263
+
264
+ client.persist_session(
265
+ execution_id="exec_123",
266
+ session_id="session_456",
267
+ user_id="user_789",
268
+ messages=messages,
269
+ metadata=metadata
270
+ )
271
+
272
+ # Check payload
273
+ call_args = mock_http_server.post.call_args
274
+ payload = call_args[1]["json"]
275
+
276
+ assert payload["session_id"] == "session_456"
277
+ assert payload["user_id"] == "user_789"
278
+ assert payload["messages"] == messages
279
+ assert payload["metadata"] == metadata
280
+
281
+ def test_skills_request_format(self, mock_http_server):
282
+ """Test that skills request is properly formatted"""
283
+ client = ControlPlaneClient(
284
+ base_url="http://localhost:8000",
285
+ api_key="test_key"
286
+ )
287
+
288
+ mock_response = Mock()
289
+ mock_response.status_code = 200
290
+ mock_response.json = Mock(return_value=[])
291
+ mock_http_server.get = Mock(return_value=mock_response)
292
+
293
+ # Fetch skills
294
+ client.get_skills(agent_id="agent_abc123")
295
+
296
+ # Check URL
297
+ call_args = mock_http_server.get.call_args
298
+ url = call_args[0][0]
299
+ assert "agent_abc123" in url
300
+ assert "skills/resolved" in url
301
+
302
+ # Check headers
303
+ headers = call_args[1]["headers"]
304
+ assert "Authorization" in headers
305
+
306
+
307
+ if __name__ == "__main__":
308
+ pytest.main([__file__, "-v"])
File without changes