codemie-sdk-python 0.1.226__py3-none-any.whl → 0.1.273__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.
@@ -0,0 +1,375 @@
1
+ """Vendor guardrail service implementation for managing cloud vendor guardrail settings."""
2
+
3
+ from typing import Union, Optional, List
4
+
5
+ from ..models.vendor_assistant import VendorType
6
+ from ..models.vendor_guardrail import (
7
+ VendorGuardrailSettingsResponse,
8
+ VendorGuardrailsResponse,
9
+ VendorGuardrail,
10
+ VendorGuardrailVersion,
11
+ VendorGuardrailVersionsResponse,
12
+ VendorGuardrailInstallRequest,
13
+ VendorGuardrailInstallResponse,
14
+ VendorGuardrailUninstallResponse,
15
+ )
16
+ from ..utils import ApiRequestHandler
17
+
18
+
19
+ class VendorGuardrailService:
20
+ """Service for managing cloud vendor guardrail settings (AWS, Azure, GCP)."""
21
+
22
+ def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
23
+ """Initialize the vendor guardrail service.
24
+
25
+ Args:
26
+ api_domain: Base URL for the CodeMie API
27
+ token: Authentication token
28
+ verify_ssl: Whether to verify SSL certificates
29
+ """
30
+ self._api = ApiRequestHandler(api_domain, token, verify_ssl)
31
+
32
+ def get_guardrail_settings(
33
+ self,
34
+ vendor: Union[VendorType, str],
35
+ page: int = 0,
36
+ per_page: int = 10,
37
+ ) -> VendorGuardrailSettingsResponse:
38
+ """Get guardrail settings for a specific cloud vendor.
39
+
40
+ Args:
41
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
42
+ page: Page number for pagination (0-based)
43
+ per_page: Number of items per page
44
+
45
+ Returns:
46
+ VendorGuardrailSettingsResponse containing list of settings and pagination info
47
+
48
+ Example:
49
+ >>> # Using enum
50
+ >>> settings = client.vendor_guardrails.get_guardrail_settings(VendorType.AWS, page=0, per_page=10)
51
+ >>> # Using string
52
+ >>> settings = client.vendor_guardrails.get_guardrail_settings("aws", page=0, per_page=10)
53
+ >>> # Access settings data
54
+ >>> for setting in settings.data:
55
+ ... print(f"Setting: {setting.setting_name}, Project: {setting.project}")
56
+ ... if setting.invalid:
57
+ ... print(f"Error: {setting.error}")
58
+ """
59
+ # Convert enum to string value if needed
60
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
61
+
62
+ params = {
63
+ "page": page,
64
+ "per_page": per_page,
65
+ }
66
+
67
+ return self._api.get(
68
+ f"/v1/vendors/{vendor_str}/guardrails/settings",
69
+ VendorGuardrailSettingsResponse,
70
+ params=params,
71
+ wrap_response=False,
72
+ )
73
+
74
+ def get_guardrails(
75
+ self,
76
+ vendor: Union[VendorType, str],
77
+ setting_id: str,
78
+ per_page: int = 10,
79
+ next_token: Optional[str] = None,
80
+ ) -> VendorGuardrailsResponse:
81
+ """Get guardrails for a specific vendor setting.
82
+
83
+ Args:
84
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
85
+ setting_id: ID of the vendor setting to retrieve guardrails for
86
+ per_page: Number of items per page
87
+ next_token: Token for pagination (optional, for retrieving next page)
88
+
89
+ Returns:
90
+ VendorGuardrailsResponse containing list of guardrails and pagination token
91
+
92
+ Example:
93
+ >>> # Get first page
94
+ >>> guardrails = client.vendor_guardrails.get_guardrails(
95
+ ... vendor=VendorType.AWS,
96
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
97
+ ... per_page=8
98
+ ... )
99
+ >>> # Access guardrail data
100
+ >>> for guardrail in guardrails.data:
101
+ ... print(f"Name: {guardrail.name}, Status: {guardrail.status}")
102
+ ... print(f"Version: {guardrail.version}, Description: {guardrail.description}")
103
+ >>> # Get next page if available
104
+ >>> if guardrails.pagination.next_token:
105
+ ... next_page = client.vendor_guardrails.get_guardrails(
106
+ ... vendor=VendorType.AWS,
107
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
108
+ ... per_page=8,
109
+ ... next_token=guardrails.pagination.next_token
110
+ ... )
111
+ """
112
+ # Convert enum to string value if needed
113
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
114
+
115
+ params = {
116
+ "setting_id": setting_id,
117
+ "per_page": per_page,
118
+ }
119
+
120
+ if next_token:
121
+ params["next_token"] = next_token
122
+
123
+ return self._api.get(
124
+ f"/v1/vendors/{vendor_str}/guardrails",
125
+ VendorGuardrailsResponse,
126
+ params=params,
127
+ wrap_response=False,
128
+ )
129
+
130
+ def get_guardrail(
131
+ self,
132
+ vendor: Union[VendorType, str],
133
+ guardrail_id: str,
134
+ setting_id: str,
135
+ ) -> VendorGuardrail:
136
+ """Get a specific guardrail by ID for a vendor setting.
137
+
138
+ Args:
139
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
140
+ guardrail_id: ID of the guardrail to retrieve
141
+ setting_id: ID of the vendor setting
142
+
143
+ Returns:
144
+ VendorGuardrail containing guardrail details
145
+
146
+ Example:
147
+ >>> guardrail = client.vendor_guardrails.get_guardrail(
148
+ ... vendor=VendorType.AWS,
149
+ ... guardrail_id="lss9vxro9oxg",
150
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c"
151
+ ... )
152
+ >>> print(f"Name: {guardrail.name}, Status: {guardrail.status}")
153
+ >>> print(f"Version: {guardrail.version}, Description: {guardrail.description}")
154
+ """
155
+ # Convert enum to string value if needed
156
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
157
+
158
+ params = {
159
+ "setting_id": setting_id,
160
+ }
161
+
162
+ return self._api.get(
163
+ f"/v1/vendors/{vendor_str}/guardrails/{guardrail_id}",
164
+ VendorGuardrail,
165
+ params=params,
166
+ wrap_response=False,
167
+ )
168
+
169
+ def get_guardrail_version(
170
+ self,
171
+ vendor: Union[VendorType, str],
172
+ guardrail_id: str,
173
+ version: str,
174
+ setting_id: str,
175
+ ) -> VendorGuardrailVersion:
176
+ """Get a specific version of a vendor guardrail with detailed information.
177
+
178
+ Args:
179
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
180
+ guardrail_id: ID of the guardrail to retrieve
181
+ version: Version number to retrieve (e.g., "1", "2", "DRAFT")
182
+ setting_id: ID of the vendor setting
183
+
184
+ Returns:
185
+ VendorGuardrailVersion containing detailed version information including
186
+ blocked messaging settings and timestamps
187
+
188
+ Example:
189
+ >>> version_details = client.vendor_guardrails.get_guardrail_version(
190
+ ... vendor=VendorType.AWS,
191
+ ... guardrail_id="lss9vxro9oxg",
192
+ ... version="1",
193
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c"
194
+ ... )
195
+ >>> print(f"Name: {version_details.name}")
196
+ >>> print(f"Version: {version_details.version}")
197
+ >>> print(f"Status: {version_details.status}")
198
+ >>> print(f"Blocked Input Message: {version_details.blockedInputMessaging}")
199
+ >>> print(f"Blocked Output Message: {version_details.blockedOutputsMessaging}")
200
+ """
201
+ # Convert enum to string value if needed
202
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
203
+
204
+ params = {
205
+ "setting_id": setting_id,
206
+ }
207
+
208
+ return self._api.get(
209
+ f"/v1/vendors/{vendor_str}/guardrails/{guardrail_id}/{version}",
210
+ VendorGuardrailVersion,
211
+ params=params,
212
+ wrap_response=False,
213
+ )
214
+
215
+ def get_guardrail_versions(
216
+ self,
217
+ vendor: Union[VendorType, str],
218
+ guardrail_id: str,
219
+ setting_id: str,
220
+ per_page: int = 10,
221
+ next_token: Optional[str] = None,
222
+ ) -> VendorGuardrailVersionsResponse:
223
+ """Get versions for a specific vendor guardrail.
224
+
225
+ Args:
226
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
227
+ guardrail_id: ID of the guardrail to retrieve versions for
228
+ setting_id: ID of the vendor setting
229
+ per_page: Number of items per page
230
+ next_token: Token for pagination (optional, for retrieving next page)
231
+
232
+ Returns:
233
+ VendorGuardrailVersionsResponse containing list of versions and pagination token
234
+
235
+ Example:
236
+ >>> # Get first page of versions
237
+ >>> versions = client.vendor_guardrails.get_guardrail_versions(
238
+ ... vendor=VendorType.AWS,
239
+ ... guardrail_id="lss9vxro9oxg",
240
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
241
+ ... per_page=5
242
+ ... )
243
+ >>> for version in versions.data:
244
+ ... print(f"{version.name} (v{version.version}): {version.status}")
245
+ >>> # Get next page if available
246
+ >>> if versions.pagination.next_token:
247
+ ... next_page = client.vendor_guardrails.get_guardrail_versions(
248
+ ... vendor=VendorType.AWS,
249
+ ... guardrail_id="lss9vxro9oxg",
250
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c",
251
+ ... per_page=5,
252
+ ... next_token=versions.pagination.next_token
253
+ ... )
254
+ """
255
+ # Convert enum to string value if needed
256
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
257
+
258
+ params = {
259
+ "setting_id": setting_id,
260
+ "per_page": per_page,
261
+ }
262
+
263
+ if next_token:
264
+ params["next_token"] = next_token
265
+
266
+ return self._api.get(
267
+ f"/v1/vendors/{vendor_str}/guardrails/{guardrail_id}/versions",
268
+ VendorGuardrailVersionsResponse,
269
+ params=params,
270
+ wrap_response=False,
271
+ )
272
+
273
+ def install_guardrails(
274
+ self,
275
+ vendor: Union[VendorType, str],
276
+ guardrails: List[VendorGuardrailInstallRequest],
277
+ ) -> VendorGuardrailInstallResponse:
278
+ """Install/activate vendor guardrails.
279
+
280
+ Args:
281
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
282
+ guardrails: List of guardrail installation requests with guardrail ID, version, and setting ID
283
+
284
+ Returns:
285
+ VendorGuardrailInstallResponse containing installation summary with AI run IDs
286
+
287
+ Example:
288
+ >>> from codemie_sdk import VendorGuardrailInstallRequest
289
+ >>> # Install single guardrail
290
+ >>> install_request = VendorGuardrailInstallRequest(
291
+ ... id="lss9vxro9oxg",
292
+ ... version="1",
293
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c"
294
+ ... )
295
+ >>> response = client.vendor_guardrails.install_guardrails(
296
+ ... vendor=VendorType.AWS,
297
+ ... guardrails=[install_request]
298
+ ... )
299
+ >>> for item in response.summary:
300
+ ... print(f"Installed {item.guardrailId} version {item.version} with run ID: {item.aiRunId}")
301
+ >>>
302
+ >>> # Install multiple guardrails
303
+ >>> requests = [
304
+ ... VendorGuardrailInstallRequest(
305
+ ... id="GUARDRAIL_ID_1",
306
+ ... version="1",
307
+ ... setting_id="SETTING_ID"
308
+ ... ),
309
+ ... VendorGuardrailInstallRequest(
310
+ ... id="GUARDRAIL_ID_2",
311
+ ... version="2",
312
+ ... setting_id="SETTING_ID"
313
+ ... )
314
+ ... ]
315
+ >>> response = client.vendor_guardrails.install_guardrails(
316
+ ... vendor=VendorType.AWS,
317
+ ... guardrails=requests
318
+ ... )
319
+ """
320
+ # Convert enum to string value if needed
321
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
322
+
323
+ # Convert list of Pydantic models to list of dicts
324
+ payload = [guardrail.model_dump(by_alias=True) for guardrail in guardrails]
325
+
326
+ return self._api.post(
327
+ f"/v1/vendors/{vendor_str}/guardrails",
328
+ VendorGuardrailInstallResponse,
329
+ json_data=payload,
330
+ wrap_response=False,
331
+ )
332
+
333
+ def uninstall_guardrail(
334
+ self,
335
+ vendor: Union[VendorType, str],
336
+ ai_run_id: str,
337
+ ) -> VendorGuardrailUninstallResponse:
338
+ """Uninstall/deactivate a vendor guardrail.
339
+
340
+ Args:
341
+ vendor: Cloud vendor type (aws, azure, gcp). Can be VendorType enum or string.
342
+ ai_run_id: AI run ID returned from the install operation
343
+
344
+ Returns:
345
+ VendorGuardrailUninstallResponse with success status
346
+
347
+ Example:
348
+ >>> # First, install a guardrail
349
+ >>> install_request = VendorGuardrailInstallRequest(
350
+ ... id="lss9vxro9oxg",
351
+ ... version="1",
352
+ ... setting_id="cac90788-39b7-4ffe-8b57-e8b047fa1f6c"
353
+ ... )
354
+ >>> install_response = client.vendor_guardrails.install_guardrails(
355
+ ... vendor=VendorType.AWS,
356
+ ... guardrails=[install_request]
357
+ ... )
358
+ >>> ai_run_id = install_response.summary[0].aiRunId
359
+ >>>
360
+ >>> # Later, uninstall the guardrail using the AI run ID
361
+ >>> response = client.vendor_guardrails.uninstall_guardrail(
362
+ ... vendor=VendorType.AWS,
363
+ ... ai_run_id=ai_run_id
364
+ ... )
365
+ >>> if response.success:
366
+ ... print("Guardrail successfully uninstalled!")
367
+ """
368
+ # Convert enum to string value if needed
369
+ vendor_str = vendor.value if isinstance(vendor, VendorType) else vendor
370
+
371
+ return self._api.delete(
372
+ f"/v1/vendors/{vendor_str}/guardrails/{ai_run_id}",
373
+ VendorGuardrailUninstallResponse,
374
+ wrap_response=False,
375
+ )
@@ -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
@@ -1,12 +1,11 @@
1
1
  """HTTP utilities for CodeMie SDK."""
2
2
 
3
- from typing import TypeVar, Type, Optional, Any, Union, Dict, List, get_origin, get_args
4
- from pydantic import BaseModel
3
+ from typing import TypeVar, Type, Optional, Any, Dict, List, get_origin, get_args
5
4
  import requests
6
5
  import logging
7
6
  from functools import wraps
8
7
 
9
- T = TypeVar("T", bound=Union[BaseModel, List[BaseModel], dict])
8
+ T = TypeVar("T")
10
9
 
11
10
  logger = logging.getLogger(__name__)
12
11
 
@@ -55,6 +54,7 @@ class ApiRequestHandler:
55
54
  "localhost",
56
55
  "127.0.0.1",
57
56
  "0.0.0.0",
57
+ "192.168",
58
58
  ]
59
59
  return any(pattern in domain_lower for pattern in localhost_patterns)
60
60
 
@@ -138,7 +138,7 @@ class ApiRequestHandler:
138
138
  wrap_response: Whether response is wrapped in 'data' field
139
139
 
140
140
  Returns:
141
- Parsed response object or list of objects
141
+ Parsed response object or list of objects, or raw Response if response_model is requests.Response
142
142
  """
143
143
  if params:
144
144
  logger.debug(f"Request params: {params}")
@@ -150,6 +150,9 @@ class ApiRequestHandler:
150
150
  )
151
151
  response.raise_for_status()
152
152
 
153
+ if response_model is None or response_model is requests.Response:
154
+ return response
155
+
153
156
  return self._parse_response(response, response_model, wrap_response)
154
157
 
155
158
  @log_request
@@ -161,7 +164,8 @@ class ApiRequestHandler:
161
164
  stream: bool = False,
162
165
  wrap_response: bool = True,
163
166
  raise_on_error: bool = True,
164
- ) -> Union[T, requests.Response]:
167
+ extra_headers: Optional[Dict[str, str]] = None,
168
+ ) -> T:
165
169
  """Makes a POST request and parses the response.
166
170
 
167
171
  Args:
@@ -171,6 +175,7 @@ class ApiRequestHandler:
171
175
  stream: Whether to return streaming response
172
176
  wrap_response: Whether response is wrapped in 'data' field
173
177
  raise_on_error: Whether to raise exception on HTTP error status codes
178
+ extra_headers: Optional additional HTTP headers to include (e.g., X-* for MCP propagation)
174
179
 
175
180
  Returns:
176
181
  Parsed response object/list or streaming response
@@ -178,9 +183,13 @@ class ApiRequestHandler:
178
183
  if json_data:
179
184
  logger.debug(f"Request body: {json_data}")
180
185
 
186
+ headers = self._get_headers()
187
+ if extra_headers:
188
+ headers.update(extra_headers)
189
+
181
190
  response = requests.post(
182
191
  url=f"{self._base_url}{endpoint}",
183
- headers=self._get_headers(),
192
+ headers=headers,
184
193
  json=json_data,
185
194
  verify=self._verify_ssl,
186
195
  stream=stream,
@@ -242,6 +251,7 @@ class ApiRequestHandler:
242
251
  json_data: Dict[str, Any],
243
252
  params: Optional[Dict[str, Any]] = None,
244
253
  wrap_response: bool = True,
254
+ extra_headers: Optional[Dict[str, str]] = None,
245
255
  ) -> T:
246
256
  """Makes a PUT request and parses the response.
247
257
 
@@ -251,14 +261,18 @@ class ApiRequestHandler:
251
261
  json_data: JSON request body
252
262
  params: Query parameters
253
263
  wrap_response: Whether response is wrapped in 'data' field
264
+ extra_headers: Optional additional HTTP headers to include (e.g., X-* for MCP propagation)
254
265
 
255
266
  Returns:
256
267
  Parsed response object or list of objects
257
268
  """
258
269
  logger.debug(f"Request body: {json_data}")
270
+ headers = self._get_headers()
271
+ if extra_headers:
272
+ headers.update(extra_headers)
259
273
  response = requests.put(
260
274
  url=f"{self._base_url}{endpoint}",
261
- headers=self._get_headers(),
275
+ headers=headers,
262
276
  json=json_data,
263
277
  params=params,
264
278
  verify=self._verify_ssl,