codemie-sdk-python 0.1.204__py3-none-any.whl → 0.1.230__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 codemie-sdk-python might be problematic. Click here for more details.

@@ -0,0 +1,330 @@
1
+ """Vendor workflow service implementation for managing cloud vendor workflow settings."""
2
+
3
+ from typing import Union, Optional, List
4
+
5
+ from ..models.vendor_assistant import VendorType
6
+ from ..models.vendor_workflow import (
7
+ VendorWorkflowSettingsResponse,
8
+ VendorWorkflowsResponse,
9
+ VendorWorkflow,
10
+ VendorWorkflowAliasesResponse,
11
+ VendorWorkflowInstallRequest,
12
+ VendorWorkflowInstallResponse,
13
+ VendorWorkflowUninstallResponse,
14
+ )
15
+ from ..utils import ApiRequestHandler
16
+
17
+
18
+ class VendorWorkflowService:
19
+ """Service for managing cloud vendor workflow settings (AWS, Azure, GCP)."""
20
+
21
+ def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
22
+ """Initialize the vendor workflow service.
23
+
24
+ Args:
25
+ api_domain: Base URL for the CodeMie API
26
+ token: Authentication token
27
+ verify_ssl: Whether to verify SSL certificates
28
+ """
29
+ self._api = ApiRequestHandler(api_domain, token, verify_ssl)
30
+
31
+ def get_workflow_settings(
32
+ self,
33
+ vendor: Union[VendorType, str],
34
+ page: int = 0,
35
+ per_page: int = 10,
36
+ ) -> VendorWorkflowSettingsResponse:
37
+ """Get workflow settings for a specific cloud vendor.
38
+
39
+ Args:
40
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
41
+ page: Page number for pagination (0-based)
42
+ per_page: Number of items per page
43
+
44
+ Returns:
45
+ VendorWorkflowSettingsResponse containing list of settings and pagination info
46
+
47
+ Example:
48
+ >>> # Using enum
49
+ >>> settings = client.vendor_workflows.get_workflow_settings(VendorType.AWS, page=0, per_page=10)
50
+ >>> # Using string
51
+ >>> settings = client.vendor_workflows.get_workflow_settings("aws", page=0, per_page=10)
52
+ >>> # Access settings data
53
+ >>> for setting in settings.data:
54
+ ... print(f"Setting: {setting.setting_name}, Project: {setting.project}")
55
+ ... if setting.invalid:
56
+ ... print(f"Error: {setting.error}")
57
+ """
58
+ # Convert enum to string value if needed
59
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
60
+
61
+ params = {
62
+ "page": page,
63
+ "per_page": per_page,
64
+ }
65
+
66
+ return self._api.get(
67
+ f"/v1/vendors/{vendor_str}/workflows/settings",
68
+ VendorWorkflowSettingsResponse,
69
+ params=params,
70
+ wrap_response=False,
71
+ )
72
+
73
+ def get_workflows(
74
+ self,
75
+ vendor: Union[VendorType, str],
76
+ setting_id: str,
77
+ per_page: int = 10,
78
+ next_token: Optional[str] = None,
79
+ ) -> VendorWorkflowsResponse:
80
+ """Get workflows for a specific vendor setting.
81
+
82
+ Args:
83
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
84
+ setting_id: ID of the vendor setting to retrieve workflows for
85
+ per_page: Number of items per page
86
+ next_token: Token for pagination (optional, for retrieving next page)
87
+
88
+ Returns:
89
+ VendorWorkflowsResponse containing list of workflows and pagination token
90
+
91
+ Example:
92
+ >>> # Get first page
93
+ >>> workflows = client.vendor_workflows.get_workflows(
94
+ ... vendor=VendorType.AWS,
95
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
96
+ ... per_page=8
97
+ ... )
98
+ >>> # Access workflow data
99
+ >>> for workflow in workflows.data:
100
+ ... print(f"Name: {workflow.name}, Status: {workflow.status}")
101
+ ... print(f"Version: {workflow.version}, Description: {workflow.description}")
102
+ >>> # Get next page if available
103
+ >>> if workflows.pagination.next_token:
104
+ ... next_page = client.vendor_workflows.get_workflows(
105
+ ... vendor=VendorType.AWS,
106
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
107
+ ... per_page=8,
108
+ ... next_token=workflows.pagination.next_token
109
+ ... )
110
+ """
111
+ # Convert enum to string value if needed
112
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
113
+
114
+ params = {
115
+ "setting_id": setting_id,
116
+ "per_page": per_page,
117
+ }
118
+
119
+ if next_token:
120
+ params["next_token"] = next_token
121
+
122
+ return self._api.get(
123
+ f"/v1/vendors/{vendor_str}/workflows",
124
+ VendorWorkflowsResponse,
125
+ params=params,
126
+ wrap_response=False,
127
+ )
128
+
129
+ def get_workflow(
130
+ self,
131
+ vendor: Union[VendorType, str],
132
+ workflow_id: str,
133
+ setting_id: str,
134
+ ) -> VendorWorkflow:
135
+ """Get a specific workflow by ID for a vendor setting.
136
+
137
+ Args:
138
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
139
+ workflow_id: ID of the workflow to retrieve
140
+ setting_id: ID of the vendor setting
141
+
142
+ Returns:
143
+ VendorWorkflow containing workflow details
144
+
145
+ Example:
146
+ >>> workflow = client.vendor_workflows.get_workflow(
147
+ ... vendor=VendorType.AWS,
148
+ ... workflow_id="9HXLQ7J9YP",
149
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c"
150
+ ... )
151
+ >>> print(f"Name: {workflow.name}, Status: {workflow.status}")
152
+ >>> print(f"Version: {workflow.version}, Description: {workflow.description}")
153
+ """
154
+ # Convert enum to string value if needed
155
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
156
+
157
+ params = {
158
+ "setting_id": setting_id,
159
+ }
160
+
161
+ return self._api.get(
162
+ f"/v1/vendors/{vendor_str}/workflows/{workflow_id}",
163
+ VendorWorkflow,
164
+ params=params,
165
+ wrap_response=False,
166
+ )
167
+
168
+ def get_workflow_aliases(
169
+ self,
170
+ vendor: Union[VendorType, str],
171
+ workflow_id: str,
172
+ setting_id: str,
173
+ per_page: int = 10,
174
+ next_token: Optional[str] = None,
175
+ ) -> VendorWorkflowAliasesResponse:
176
+ """Get aliases for a specific vendor workflow.
177
+
178
+ Args:
179
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
180
+ workflow_id: ID of the workflow to retrieve aliases for
181
+ setting_id: ID of the vendor setting
182
+ per_page: Number of items per page
183
+ next_token: Token for pagination (optional, for retrieving next page)
184
+
185
+ Returns:
186
+ VendorWorkflowAliasesResponse containing list of aliases and pagination token
187
+
188
+ Example:
189
+ >>> # Get first page of aliases
190
+ >>> aliases = client.vendor_workflows.get_workflow_aliases(
191
+ ... vendor=VendorType.AWS,
192
+ ... workflow_id="9HXLQ7J9YP",
193
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
194
+ ... per_page=5
195
+ ... )
196
+ >>> for alias in aliases.data:
197
+ ... print(f"{alias.name} (v{alias.version}): {alias.status}")
198
+ ... if alias.aiRunId:
199
+ ... print(f" AI Run ID: {alias.aiRunId}")
200
+ >>> # Get next page if available
201
+ >>> if aliases.pagination.next_token:
202
+ ... next_page = client.vendor_workflows.get_workflow_aliases(
203
+ ... vendor=VendorType.AWS,
204
+ ... workflow_id="9HXLQ7J9YP",
205
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
206
+ ... per_page=5,
207
+ ... next_token=aliases.pagination.next_token
208
+ ... )
209
+ """
210
+ # Convert enum to string value if needed
211
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
212
+
213
+ params = {
214
+ "setting_id": setting_id,
215
+ "per_page": per_page,
216
+ }
217
+
218
+ if next_token:
219
+ params["next_token"] = next_token
220
+
221
+ return self._api.get(
222
+ f"/v1/vendors/{vendor_str}/workflows/{workflow_id}/aliases",
223
+ VendorWorkflowAliasesResponse,
224
+ params=params,
225
+ wrap_response=False,
226
+ )
227
+
228
+ def install_workflows(
229
+ self,
230
+ vendor: Union[VendorType, str],
231
+ workflows: List[VendorWorkflowInstallRequest],
232
+ ) -> VendorWorkflowInstallResponse:
233
+ """Install/activate vendor workflows.
234
+
235
+ Args:
236
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
237
+ workflows: List of workflow installation requests with workflow ID, flow alias ID, and setting ID
238
+
239
+ Returns:
240
+ VendorWorkflowInstallResponse containing installation summary with AI run IDs
241
+
242
+ Example:
243
+ >>> from codemie_sdk import VendorWorkflowInstallRequest
244
+ >>> # Install single workflow
245
+ >>> install_request = VendorWorkflowInstallRequest(
246
+ ... id="9HXLQ7J9YP",
247
+ ... flowAliasId="9RUV0BI2L7",
248
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c"
249
+ ... )
250
+ >>> response = client.vendor_workflows.install_workflows(
251
+ ... vendor=VendorType.AWS,
252
+ ... workflows=[install_request]
253
+ ... )
254
+ >>> for item in response.summary:
255
+ ... print(f"Installed workflow {item.flowId} with run ID: {item.aiRunId}")
256
+ >>>
257
+ >>> # Install multiple workflows
258
+ >>> requests = [
259
+ ... VendorWorkflowInstallRequest(
260
+ ... id="WORKFLOW_ID_1",
261
+ ... flowAliasId="ALIAS_ID_1",
262
+ ... setting_id="SETTING_ID"
263
+ ... ),
264
+ ... VendorWorkflowInstallRequest(
265
+ ... id="WORKFLOW_ID_2",
266
+ ... flowAliasId="ALIAS_ID_2",
267
+ ... setting_id="SETTING_ID"
268
+ ... )
269
+ ... ]
270
+ >>> response = client.vendor_workflows.install_workflows(
271
+ ... vendor=VendorType.AWS,
272
+ ... workflows=requests
273
+ ... )
274
+ """
275
+ # Convert enum to string value if needed
276
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
277
+
278
+ # Convert list of Pydantic models to list of dicts
279
+ payload = [workflow.model_dump(by_alias=True) for workflow in workflows]
280
+
281
+ return self._api.post(
282
+ f"/v1/vendors/{vendor_str}/workflows",
283
+ VendorWorkflowInstallResponse,
284
+ json_data=payload,
285
+ wrap_response=False,
286
+ )
287
+
288
+ def uninstall_workflow(
289
+ self,
290
+ vendor: Union[VendorType, str],
291
+ ai_run_id: str,
292
+ ) -> VendorWorkflowUninstallResponse:
293
+ """Uninstall/deactivate a vendor workflow.
294
+
295
+ Args:
296
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
297
+ ai_run_id: AI run ID returned from the workflow alias (aiRunId field)
298
+
299
+ Returns:
300
+ VendorWorkflowUninstallResponse with success status
301
+
302
+ Example:
303
+ >>> # Get workflow aliases to find the aiRunId
304
+ >>> aliases = client.vendor_workflows.get_workflow_aliases(
305
+ ... vendor=VendorType.AWS,
306
+ ... workflow_id="9HXLQ7J9YP",
307
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c"
308
+ ... )
309
+ >>> # Find an installed alias with aiRunId
310
+ >>> for alias in aliases.data:
311
+ ... if alias.aiRunId:
312
+ ... ai_run_id = alias.aiRunId
313
+ ... break
314
+ >>>
315
+ >>> # Uninstall the workflow using the AI run ID
316
+ >>> response = client.vendor_workflows.uninstall_workflow(
317
+ ... vendor=VendorType.AWS,
318
+ ... ai_run_id="56fed66d-f66e-46e3-b420-bb3a8d93eed4"
319
+ ... )
320
+ >>> if response.success:
321
+ ... print("Workflow successfully uninstalled!")
322
+ """
323
+ # Convert enum to string value if needed
324
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
325
+
326
+ return self._api.delete(
327
+ f"/v1/vendors/{vendor_str}/workflows/{ai_run_id}",
328
+ VendorWorkflowUninstallResponse,
329
+ wrap_response=False,
330
+ )
@@ -0,0 +1,41 @@
1
+ import requests
2
+
3
+ from typing import Dict, Any
4
+ from ..utils import ApiRequestHandler
5
+
6
+
7
+ class WebhookService:
8
+ """Webhook service implementation."""
9
+
10
+ def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
11
+ """Initialize the conversation service.
12
+
13
+ Args:
14
+ api_domain: Base URL for the API
15
+ token: Authentication token
16
+ verify_ssl: Whether to verify SSL certificates
17
+ """
18
+ self._api = ApiRequestHandler(api_domain, token, verify_ssl)
19
+
20
+ def trigger(
21
+ self, webhook_id: str, data: Dict[str, Any] = None
22
+ ) -> requests.Response:
23
+ """Trigger a webhook by sending a POST request with the provided data.
24
+
25
+ Args:
26
+ webhook_id: Webhook ID to trigger
27
+ data: Request body data. Defaults to {"test": "data"} if not provided
28
+
29
+ Returns:
30
+ Response object from requests library
31
+ """
32
+ if data is None:
33
+ data = {"test": "data"}
34
+
35
+ return self._api.post(
36
+ f"/v1/webhooks/{webhook_id}",
37
+ response_model=requests.Response,
38
+ json_data=data,
39
+ wrap_response=False,
40
+ raise_on_error=False,
41
+ )
@@ -135,6 +135,8 @@ class WorkflowService:
135
135
  workflow_id: str,
136
136
  user_input: Optional[str] = None,
137
137
  file_name: Optional[str] = None,
138
+ propagate_headers: bool = False,
139
+ headers: Optional[dict[str, str]] = None,
138
140
  ) -> dict:
139
141
  """Run a workflow with optional input parameters.
140
142
 
@@ -142,11 +144,18 @@ class WorkflowService:
142
144
  workflow_id: ID of the workflow to run
143
145
  user_input: Optional user input for the workflow execution
144
146
  file_name: Optional file name for the workflow execution
147
+ propagate_headers: Enable propagation of X-* HTTP headers to MCP servers
148
+ headers: Optional additional HTTP headers (e.g., X-* for MCP propagation)
145
149
 
146
150
  Returns:
147
151
  dict: Created workflow execution details
148
152
  """
149
- return self.executions(workflow_id).create(user_input, file_name)
153
+ return self.executions(workflow_id).create(
154
+ user_input=user_input,
155
+ file_name=file_name,
156
+ propagate_headers=propagate_headers,
157
+ headers=headers,
158
+ )
150
159
 
151
160
  def executions(self, workflow_id: str) -> WorkflowExecutionService:
152
161
  """Get workflow execution service for the specified workflow.
@@ -46,24 +46,33 @@ class WorkflowExecutionService:
46
46
  )
47
47
 
48
48
  def create(
49
- self, user_input: Optional[str] = None, file_name: Optional[str] = None
49
+ self,
50
+ user_input: Optional[str] = None,
51
+ file_name: Optional[str] = None,
52
+ propagate_headers: bool = False,
53
+ headers: Optional[dict[str, str]] = None,
50
54
  ) -> dict:
51
55
  """Create a new workflow execution.
52
56
 
53
57
  Args:
54
58
  user_input: Optional input data for the workflow execution.
55
59
  file_name: Optional file name associated with the workflow execution.
60
+ propagate_headers: Enable propagation of X-* HTTP headers to MCP servers.
61
+ headers: Optional additional HTTP headers (e.g., X-* for MCP propagation)
56
62
 
57
63
  Returns:
58
64
  dict: Created workflow execution details
59
65
  """
60
66
  payload = WorkflowExecutionCreateRequest(
61
- user_input=user_input, file_name=file_name
67
+ user_input=user_input,
68
+ file_name=file_name,
69
+ propagate_headers=propagate_headers,
62
70
  )
63
71
  return self._api.post(
64
72
  f"/v1/workflows/{self._workflow_id}/executions",
65
73
  dict,
66
74
  json_data=payload.model_dump(),
75
+ extra_headers=headers,
67
76
  )
68
77
 
69
78
  def get(self, execution_id: str) -> WorkflowExecution:
@@ -108,17 +117,30 @@ class WorkflowExecutionService:
108
117
  f"/v1/workflows/{self._workflow_id}/executions/{execution_id}/abort", dict
109
118
  )
110
119
 
111
- def resume(self, execution_id: str) -> dict:
120
+ def resume(
121
+ self,
122
+ execution_id: str,
123
+ propagate_headers: bool = False,
124
+ headers: Optional[dict[str, str]] = None,
125
+ ) -> dict:
112
126
  """Resume an interrupted workflow execution.
113
127
 
114
128
  Args:
115
129
  execution_id: ID of the execution to resume
130
+ propagate_headers: Enable propagation of X-* HTTP headers to MCP servers.
131
+ headers: Optional additional HTTP headers (e.g., X-* for MCP propagation)
116
132
 
117
133
  Returns:
118
134
  dict: Updated workflow execution details
119
135
  """
136
+ params = {"propagate_headers": propagate_headers}
137
+ # Empty body per API; passing empty dict to satisfy typing
120
138
  return self._api.put(
121
- f"/v1/workflows/{self._workflow_id}/executions/{execution_id}/resume", dict
139
+ f"/v1/workflows/{self._workflow_id}/executions/{execution_id}/resume",
140
+ dict,
141
+ json_data={},
142
+ params=params,
143
+ extra_headers=headers,
122
144
  )
123
145
 
124
146
  def get_thoughts(
codemie_sdk/utils/http.py CHANGED
@@ -160,6 +160,8 @@ class ApiRequestHandler:
160
160
  json_data: Optional[Dict[str, Any]] = None,
161
161
  stream: bool = False,
162
162
  wrap_response: bool = True,
163
+ raise_on_error: bool = True,
164
+ extra_headers: Optional[Dict[str, str]] = None,
163
165
  ) -> Union[T, requests.Response]:
164
166
  """Makes a POST request and parses the response.
165
167
 
@@ -169,6 +171,8 @@ class ApiRequestHandler:
169
171
  json_data: JSON request body
170
172
  stream: Whether to return streaming response
171
173
  wrap_response: Whether response is wrapped in 'data' field
174
+ raise_on_error: Whether to raise exception on HTTP error status codes
175
+ extra_headers: Optional additional HTTP headers to include (e.g., X-* for MCP propagation)
172
176
 
173
177
  Returns:
174
178
  Parsed response object/list or streaming response
@@ -176,18 +180,26 @@ class ApiRequestHandler:
176
180
  if json_data:
177
181
  logger.debug(f"Request body: {json_data}")
178
182
 
183
+ headers = self._get_headers()
184
+ if extra_headers:
185
+ headers.update(extra_headers)
186
+
179
187
  response = requests.post(
180
188
  url=f"{self._base_url}{endpoint}",
181
- headers=self._get_headers(),
189
+ headers=headers,
182
190
  json=json_data,
183
191
  verify=self._verify_ssl,
184
192
  stream=stream,
185
193
  )
186
- response.raise_for_status()
194
+ if raise_on_error:
195
+ response.raise_for_status()
187
196
 
188
197
  if stream:
189
198
  return response
190
199
 
200
+ if response_model is None or response_model is requests.Response:
201
+ return response
202
+
191
203
  return self._parse_response(response, response_model, wrap_response)
192
204
 
193
205
  @log_request
@@ -236,6 +248,7 @@ class ApiRequestHandler:
236
248
  json_data: Dict[str, Any],
237
249
  params: Optional[Dict[str, Any]] = None,
238
250
  wrap_response: bool = True,
251
+ extra_headers: Optional[Dict[str, str]] = None,
239
252
  ) -> T:
240
253
  """Makes a PUT request and parses the response.
241
254
 
@@ -245,14 +258,18 @@ class ApiRequestHandler:
245
258
  json_data: JSON request body
246
259
  params: Query parameters
247
260
  wrap_response: Whether response is wrapped in 'data' field
261
+ extra_headers: Optional additional HTTP headers to include (e.g., X-* for MCP propagation)
248
262
 
249
263
  Returns:
250
264
  Parsed response object or list of objects
251
265
  """
252
266
  logger.debug(f"Request body: {json_data}")
267
+ headers = self._get_headers()
268
+ if extra_headers:
269
+ headers.update(extra_headers)
253
270
  response = requests.put(
254
271
  url=f"{self._base_url}{endpoint}",
255
- headers=self._get_headers(),
272
+ headers=headers,
256
273
  json=json_data,
257
274
  params=params,
258
275
  verify=self._verify_ssl,