codemie-sdk-python 0.1.273__py3-none-any.whl → 0.1.289__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.
codemie_sdk/__init__.py CHANGED
@@ -73,10 +73,33 @@ from .models.vendor_guardrail import (
73
73
  VendorGuardrailInstallResponse,
74
74
  VendorGuardrailUninstallResponse,
75
75
  )
76
+ from .models.guardrails import (
77
+ GuardrailAssignmentSetting,
78
+ GuardrailAssignmentEntity,
79
+ GuardrailAssignmentRequest,
80
+ GuardrailAssignmentResponse,
81
+ )
82
+ from .models.analytics import (
83
+ ResponseMetadata,
84
+ PaginationMetadata,
85
+ ColumnDefinition,
86
+ Metric,
87
+ SummariesData,
88
+ TabularData,
89
+ UserListItem,
90
+ UsersListData,
91
+ SummariesResponse,
92
+ TabularResponse,
93
+ UsersListResponse,
94
+ AnalyticsQueryParams,
95
+ PaginatedAnalyticsQueryParams,
96
+ )
76
97
  from .services.vendor_assistant import VendorAssistantService
77
98
  from .services.vendor_workflow import VendorWorkflowService
78
99
  from .services.vendor_knowledgebase import VendorKnowledgeBaseService
79
100
  from .services.vendor_guardrail import VendorGuardrailService
101
+ from .services.codemie_guardrails import CodemieGuardrailService
102
+ from .services.analytics import AnalyticsService
80
103
 
81
104
  __version__ = "0.2.12"
82
105
  __all__ = [
@@ -132,4 +155,23 @@ __all__ = [
132
155
  "VendorGuardrailInstallResponse",
133
156
  "VendorGuardrailUninstallResponse",
134
157
  "VendorGuardrailService",
158
+ "GuardrailAssignmentSetting",
159
+ "GuardrailAssignmentEntity",
160
+ "GuardrailAssignmentRequest",
161
+ "GuardrailAssignmentResponse",
162
+ "CodemieGuardrailService",
163
+ "ResponseMetadata",
164
+ "PaginationMetadata",
165
+ "ColumnDefinition",
166
+ "Metric",
167
+ "SummariesData",
168
+ "TabularData",
169
+ "UserListItem",
170
+ "UsersListData",
171
+ "SummariesResponse",
172
+ "TabularResponse",
173
+ "UsersListResponse",
174
+ "AnalyticsQueryParams",
175
+ "PaginatedAnalyticsQueryParams",
176
+ "AnalyticsService",
135
177
  ]
@@ -3,6 +3,8 @@
3
3
  from typing import Optional
4
4
 
5
5
  from ..auth.credentials import KeycloakCredentials
6
+ from ..services.admin import AdminService
7
+ from ..services.analytics import AnalyticsService
6
8
  from ..services.assistant import AssistantService
7
9
  from ..services.conversation import ConversationService
8
10
  from ..services.datasource import DatasourceService
@@ -17,6 +19,7 @@ from ..services.vendor_assistant import VendorAssistantService
17
19
  from ..services.vendor_workflow import VendorWorkflowService
18
20
  from ..services.vendor_knowledgebase import VendorKnowledgeBaseService
19
21
  from ..services.vendor_guardrail import VendorGuardrailService
22
+ from ..services.codemie_guardrails import CodemieGuardrailService
20
23
 
21
24
 
22
25
  class CodeMieClient:
@@ -69,6 +72,10 @@ class CodeMieClient:
69
72
  self._token = "" if self._is_localhost else self.auth.get_token()
70
73
 
71
74
  # Initialize services with verify_ssl parameter and token
75
+ self.admin = AdminService(self._api_domain, self._token, verify_ssl=verify_ssl)
76
+ self.analytics = AnalyticsService(
77
+ self._api_domain, self._token, verify_ssl=verify_ssl
78
+ )
72
79
  self.assistants = AssistantService(
73
80
  self._api_domain, self._token, verify_ssl=verify_ssl
74
81
  )
@@ -105,6 +112,9 @@ class CodeMieClient:
105
112
  self.vendor_guardrails = VendorGuardrailService(
106
113
  self._api_domain, self._token, verify_ssl=self._verify_ssl
107
114
  )
115
+ self.codemie_guardrails = CodemieGuardrailService(
116
+ self._api_domain, self._token, verify_ssl=self._verify_ssl
117
+ )
108
118
 
109
119
  @property
110
120
  def token(self) -> str:
@@ -128,6 +138,12 @@ class CodeMieClient:
128
138
  """Force token refresh."""
129
139
  self._token = "" if self._is_localhost else self.auth.get_token()
130
140
  # Update token in services
141
+ self.admin = AdminService(
142
+ self._api_domain, self._token, verify_ssl=self._verify_ssl
143
+ )
144
+ self.analytics = AnalyticsService(
145
+ self._api_domain, self._token, verify_ssl=self._verify_ssl
146
+ )
131
147
  self.assistants = AssistantService(
132
148
  self._api_domain, self._token, verify_ssl=self._verify_ssl
133
149
  )
@@ -170,4 +186,7 @@ class CodeMieClient:
170
186
  self.vendor_guardrails = VendorGuardrailService(
171
187
  self._api_domain, self._token, verify_ssl=self._verify_ssl
172
188
  )
189
+ self.codemie_guardrails = CodemieGuardrailService(
190
+ self._api_domain, self._token, verify_ssl=self._verify_ssl
191
+ )
173
192
  return self._token
@@ -0,0 +1,28 @@
1
+ """Admin models for managing applications/projects."""
2
+
3
+ from typing import List
4
+ from pydantic import BaseModel, ConfigDict, Field
5
+
6
+
7
+ class ApplicationsListResponse(BaseModel):
8
+ """Response model for list applications endpoint."""
9
+
10
+ model_config = ConfigDict(extra="ignore")
11
+
12
+ applications: List[str] = Field(..., description="List of application names")
13
+
14
+
15
+ class ApplicationCreateRequest(BaseModel):
16
+ """Request model for creating an application/project."""
17
+
18
+ model_config = ConfigDict(extra="ignore")
19
+
20
+ name: str = Field(..., description="Application/project name")
21
+
22
+
23
+ class ApplicationCreateResponse(BaseModel):
24
+ """Response model for create application endpoint."""
25
+
26
+ model_config = ConfigDict(extra="ignore")
27
+
28
+ message: str = Field(..., description="Created application name")
@@ -0,0 +1,148 @@
1
+ """Models for analytics-related data structures."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+
8
+ class ResponseMetadata(BaseModel):
9
+ """Metadata for analytics responses."""
10
+
11
+ model_config = ConfigDict(extra="ignore")
12
+
13
+ timestamp: str = Field(description="ISO 8601 timestamp when response generated")
14
+ data_as_of: str = Field(description="ISO 8601 timestamp of data freshness")
15
+ filters_applied: Dict[str, Any] = Field(description="Applied filters")
16
+ execution_time_ms: float = Field(description="Query execution time in milliseconds")
17
+
18
+
19
+ class PaginationMetadata(BaseModel):
20
+ """Pagination metadata for tabular responses."""
21
+
22
+ model_config = ConfigDict(extra="ignore")
23
+
24
+ page: int = Field(description="Zero-indexed page number")
25
+ per_page: int = Field(description="Items per page")
26
+ total_count: int = Field(description="Total items available")
27
+ has_more: bool = Field(description="Whether more pages exist")
28
+
29
+
30
+ class ColumnDefinition(BaseModel):
31
+ """Column metadata for tabular data."""
32
+
33
+ model_config = ConfigDict(extra="ignore")
34
+
35
+ id: str = Field(description="Column identifier")
36
+ label: str = Field(description="Human-readable label")
37
+ type: str = Field(description='Data type: "string", "number", "date"')
38
+ format: Optional[str] = Field(
39
+ None, description='Format hint: "currency", "percentage", "timestamp"'
40
+ )
41
+ description: Optional[str] = Field(None, description="Column description")
42
+
43
+
44
+ class Metric(BaseModel):
45
+ """Individual metric in summary responses."""
46
+
47
+ model_config = ConfigDict(extra="ignore")
48
+
49
+ id: str = Field(description="Metric identifier")
50
+ label: str = Field(description="Human-readable label")
51
+ type: str = Field(description="Data type")
52
+ value: Any = Field(description="Metric value (int, float, str, etc.)")
53
+ format: Optional[str] = Field(
54
+ None, description='Format hint: "currency", "percentage", "number"'
55
+ )
56
+ description: Optional[str] = Field(None, description="Metric description")
57
+
58
+
59
+ class SummariesData(BaseModel):
60
+ """Container for summary metrics."""
61
+
62
+ model_config = ConfigDict(extra="ignore")
63
+
64
+ metrics: List[Metric] = Field(description="Array of metrics")
65
+
66
+
67
+ class TabularData(BaseModel):
68
+ """Container for tabular data with dynamic columns."""
69
+
70
+ model_config = ConfigDict(extra="ignore")
71
+
72
+ columns: List[ColumnDefinition] = Field(description="Column definitions")
73
+ rows: List[Dict[str, Any]] = Field(description="Data rows (dict per row)")
74
+ totals: Optional[Dict[str, Any]] = Field(None, description="Optional totals row")
75
+
76
+
77
+ class UserListItem(BaseModel):
78
+ """Individual user item."""
79
+
80
+ model_config = ConfigDict(extra="ignore")
81
+
82
+ id: str = Field(description="User ID")
83
+ name: str = Field(description="User name")
84
+
85
+
86
+ class UsersListData(BaseModel):
87
+ """Container for users list."""
88
+
89
+ model_config = ConfigDict(extra="ignore")
90
+
91
+ users: List[UserListItem] = Field(description="List of users")
92
+ total_count: int = Field(description="Total number of users")
93
+
94
+
95
+ class SummariesResponse(BaseModel):
96
+ """Response for summary endpoints (summaries, cli-summary)."""
97
+
98
+ model_config = ConfigDict(extra="ignore")
99
+
100
+ data: SummariesData = Field(description="Summary data")
101
+ metadata: ResponseMetadata = Field(description="Response metadata")
102
+
103
+
104
+ class TabularResponse(BaseModel):
105
+ """Response for tabular endpoints (19 endpoints)."""
106
+
107
+ model_config = ConfigDict(extra="ignore")
108
+
109
+ data: TabularData = Field(description="Tabular data")
110
+ metadata: ResponseMetadata = Field(description="Response metadata")
111
+ pagination: Optional[PaginationMetadata] = Field(
112
+ None, description="Optional pagination metadata"
113
+ )
114
+
115
+
116
+ class UsersListResponse(BaseModel):
117
+ """Response for users list endpoint."""
118
+
119
+ model_config = ConfigDict(extra="ignore")
120
+
121
+ data: UsersListData = Field(description="Users list data")
122
+ metadata: ResponseMetadata = Field(description="Response metadata")
123
+
124
+
125
+ class AnalyticsQueryParams(BaseModel):
126
+ """Query parameters for analytics endpoints."""
127
+
128
+ model_config = ConfigDict(extra="ignore")
129
+
130
+ time_period: Optional[str] = Field(
131
+ None,
132
+ description='Time period: "last_hour", "last_6_hours", "last_24_hours", "last_7_days", "last_30_days", "last_90_days", "last_year"',
133
+ )
134
+ start_date: Optional[str] = Field(
135
+ None, description="ISO 8601 format start date (use with end_date)"
136
+ )
137
+ end_date: Optional[str] = Field(
138
+ None, description="ISO 8601 format end date (use with start_date)"
139
+ )
140
+ users: Optional[str] = Field(None, description="Comma-separated user IDs")
141
+ projects: Optional[str] = Field(None, description="Comma-separated project names")
142
+
143
+
144
+ class PaginatedAnalyticsQueryParams(AnalyticsQueryParams):
145
+ """Query parameters with pagination."""
146
+
147
+ page: int = Field(0, description="Zero-indexed page number")
148
+ per_page: int = Field(20, description="Items per page")
@@ -216,6 +216,7 @@ class AssistantRequestBase(AssistantBase):
216
216
  mcp_servers: List[MCPServerDetails] = Field(default_factory=list)
217
217
  assistant_ids: List[str] = Field(default_factory=list)
218
218
  prompt_variables: List[PromptVariable] = Field(default_factory=list)
219
+ skip_integration_validation: Optional[bool] = Field(default=False)
219
220
 
220
221
 
221
222
  class AssistantCreateRequest(AssistantRequestBase):
@@ -230,6 +231,92 @@ class AssistantUpdateRequest(AssistantRequestBase):
230
231
  pass
231
232
 
232
233
 
234
+ class MissingIntegration(BaseModel):
235
+ """Model representing a single missing tool credential."""
236
+
237
+ model_config = ConfigDict(extra="ignore")
238
+
239
+ toolkit: str = Field(..., description="Toolkit name (e.g., 'Data Management')")
240
+ tool: str = Field(..., description="Tool name (e.g., 'sql')")
241
+ label: str = Field(..., description="Display label for the tool (e.g., 'SQL')")
242
+ credential_type: Optional[str] = Field(
243
+ None, description="Credential type required (e.g., 'AWS', 'Jira')"
244
+ )
245
+
246
+
247
+ class MissingIntegrationsByCredentialType(BaseModel):
248
+ """Model representing missing tools grouped by credential type."""
249
+
250
+ model_config = ConfigDict(extra="ignore")
251
+
252
+ credential_type: str = Field(
253
+ ..., description="Credential type (e.g., 'AWS', 'Jira', 'Confluence')"
254
+ )
255
+ missing_tools: List[MissingIntegration] = Field(
256
+ ..., description="List of missing tools requiring this credential type"
257
+ )
258
+ # Optional sub-assistant context
259
+ assistant_id: Optional[str] = Field(
260
+ None, description="Sub-assistant ID (if from sub-assistant)"
261
+ )
262
+ assistant_name: Optional[str] = Field(
263
+ None, description="Sub-assistant name (if from sub-assistant)"
264
+ )
265
+ icon_url: Optional[str] = Field(
266
+ None, description="Sub-assistant icon URL (if from sub-assistant)"
267
+ )
268
+
269
+
270
+ class IntegrationValidationResult(BaseModel):
271
+ """Complete validation result for assistant integrations."""
272
+
273
+ model_config = ConfigDict(extra="ignore")
274
+
275
+ has_missing_integrations: bool = Field(
276
+ ..., description="Whether any integrations are missing"
277
+ )
278
+ missing_by_credential_type: List[MissingIntegrationsByCredentialType] = Field(
279
+ default_factory=list,
280
+ description="Missing tools in main assistant grouped by credential type",
281
+ )
282
+ sub_assistants_missing: List[MissingIntegrationsByCredentialType] = Field(
283
+ default_factory=list,
284
+ description="Missing tools in sub-assistants grouped by credential type",
285
+ )
286
+ message: Optional[str] = Field(
287
+ None, description="User-friendly message about missing integrations"
288
+ )
289
+
290
+
291
+ class AssistantCreateResponse(BaseModel):
292
+ """Response model for assistant creation with validation."""
293
+
294
+ model_config = ConfigDict(extra="ignore", populate_by_name=True)
295
+
296
+ message: str = Field(..., description="Response message")
297
+ assistant_id: Optional[str] = Field(
298
+ None,
299
+ alias="assistantId",
300
+ description="Created assistant ID (None if validation failed)",
301
+ )
302
+ validation: Optional[IntegrationValidationResult] = Field(
303
+ None,
304
+ description="Validation result (populated if validation found missing integrations)",
305
+ )
306
+
307
+
308
+ class AssistantUpdateResponse(BaseModel):
309
+ """Response model for assistant update with validation."""
310
+
311
+ model_config = ConfigDict(extra="ignore")
312
+
313
+ message: str = Field(..., description="Response message")
314
+ validation: Optional[IntegrationValidationResult] = Field(
315
+ None,
316
+ description="Validation result (populated if validation found missing integrations)",
317
+ )
318
+
319
+
233
320
  class AssistantVersion(BaseModel):
234
321
  """Immutable snapshot of assistant configuration for a specific version."""
235
322
 
@@ -0,0 +1,62 @@
1
+ """Models for guardrail assignments."""
2
+
3
+ from typing import List
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+
8
+ class GuardrailAssignmentSetting(BaseModel):
9
+ """Model for guardrail assignment settings."""
10
+
11
+ model_config = ConfigDict(extra="ignore")
12
+
13
+ mode: str = Field(..., description="Assignment mode (e.g., 'all', 'specific')")
14
+ source: str = Field(..., description="Source type (e.g., 'input', 'output')")
15
+
16
+
17
+ class GuardrailAssignmentEntity(BaseModel):
18
+ """Model for guardrail assignment to specific entities."""
19
+
20
+ model_config = ConfigDict(extra="ignore")
21
+
22
+ settings: List[GuardrailAssignmentSetting] = Field(
23
+ default_factory=list, description="List of assignment settings"
24
+ )
25
+ items: List[str] = Field(
26
+ default_factory=list, description="List of specific entity IDs"
27
+ )
28
+
29
+
30
+ class GuardrailAssignmentRequest(BaseModel):
31
+ """Request model for assigning guardrails to entities."""
32
+
33
+ model_config = ConfigDict(extra="ignore")
34
+
35
+ project: GuardrailAssignmentEntity = Field(
36
+ default_factory=lambda: GuardrailAssignmentEntity(settings=[], items=[]),
37
+ description="Project-level assignments",
38
+ )
39
+ assistants: GuardrailAssignmentEntity = Field(
40
+ default_factory=lambda: GuardrailAssignmentEntity(settings=[], items=[]),
41
+ description="Assistant-level assignments",
42
+ )
43
+ workflows: GuardrailAssignmentEntity = Field(
44
+ default_factory=lambda: GuardrailAssignmentEntity(settings=[], items=[]),
45
+ description="Workflow-level assignments",
46
+ )
47
+ datasources: GuardrailAssignmentEntity = Field(
48
+ default_factory=lambda: GuardrailAssignmentEntity(settings=[], items=[]),
49
+ description="Datasource-level assignments",
50
+ )
51
+
52
+
53
+ class GuardrailAssignmentResponse(BaseModel):
54
+ """Response model for guardrail assignment."""
55
+
56
+ model_config = ConfigDict(extra="ignore")
57
+
58
+ success: int = Field(..., description="Count of successful assignments")
59
+ failed: int = Field(..., description="Count of failed assignments")
60
+ errors: List[str] = Field(
61
+ default_factory=list, description="List of error messages"
62
+ )
@@ -0,0 +1,60 @@
1
+ """Admin service implementation."""
2
+
3
+ from typing import List, Optional
4
+
5
+ from ..models.admin import (
6
+ ApplicationsListResponse,
7
+ ApplicationCreateRequest,
8
+ ApplicationCreateResponse,
9
+ )
10
+ from ..utils import ApiRequestHandler
11
+
12
+
13
+ class AdminService:
14
+ """Service for managing CodeMie applications/projects."""
15
+
16
+ def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
17
+ """Initialize the admin service.
18
+
19
+ Args:
20
+ api_domain: Base URL for the CodeMie API
21
+ token: Authentication token
22
+ verify_ssl: Whether to verify SSL certificates
23
+ """
24
+ self._api = ApiRequestHandler(api_domain, token, verify_ssl)
25
+
26
+ def list_applications(self, project_name: Optional[str] = None) -> List[str]:
27
+ """Get list of all applications/projects.
28
+
29
+ Args:
30
+ project_name: Optional project name to filter by
31
+
32
+ Returns:
33
+ List of application names
34
+ """
35
+ params = {}
36
+ if project_name:
37
+ params["search"] = project_name
38
+
39
+ response = self._api.get(
40
+ "/v1/admin/applications",
41
+ ApplicationsListResponse,
42
+ params=params if params else None,
43
+ )
44
+ return response.applications
45
+
46
+ def create_application(self, request: ApplicationCreateRequest) -> str:
47
+ """Create a new application/project.
48
+
49
+ Args:
50
+ request: Application creation request
51
+
52
+ Returns:
53
+ Created application name
54
+ """
55
+ response = self._api.post(
56
+ "/v1/admin/application",
57
+ ApplicationCreateResponse,
58
+ json_data=request.model_dump(exclude_none=True),
59
+ )
60
+ return response.message
@@ -0,0 +1,463 @@
1
+ """Analytics service implementation."""
2
+
3
+ from typing import Optional
4
+
5
+ from ..models.analytics import (
6
+ AnalyticsQueryParams,
7
+ PaginatedAnalyticsQueryParams,
8
+ SummariesResponse,
9
+ TabularResponse,
10
+ UsersListResponse,
11
+ )
12
+ from ..utils import ApiRequestHandler
13
+
14
+
15
+ class AnalyticsService:
16
+ """Service for managing CodeMie analytics."""
17
+
18
+ def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
19
+ """Initialize the analytics service.
20
+
21
+ Args:
22
+ api_domain: Base URL for the CodeMie API
23
+ token: Authentication token
24
+ verify_ssl: Whether to verify SSL certificates
25
+ """
26
+ self._api = ApiRequestHandler(api_domain, token, verify_ssl)
27
+
28
+ def get_summaries(
29
+ self, params: Optional[AnalyticsQueryParams] = None
30
+ ) -> SummariesResponse:
31
+ """Get overall platform summary metrics.
32
+
33
+ Args:
34
+ params: Query parameters (time filters, user/project filters)
35
+
36
+ Returns:
37
+ SummariesResponse with metrics array including total input tokens,
38
+ cached input tokens, output tokens, and money spent
39
+ """
40
+ query_params = params.model_dump(exclude_none=True) if params else {}
41
+ return self._api.get(
42
+ "/v1/analytics/summaries",
43
+ SummariesResponse,
44
+ params=query_params,
45
+ wrap_response=False,
46
+ )
47
+
48
+ def get_cli_summary(
49
+ self, params: Optional[AnalyticsQueryParams] = None
50
+ ) -> SummariesResponse:
51
+ """Get CLI-specific summary metrics.
52
+
53
+ Args:
54
+ params: Query parameters (time filters, user/project filters)
55
+
56
+ Returns:
57
+ SummariesResponse with CLI metrics including unique users, repos,
58
+ sessions, file operations, and code statistics
59
+ """
60
+ query_params = params.model_dump(exclude_none=True) if params else {}
61
+ return self._api.get(
62
+ "/v1/analytics/cli-summary",
63
+ SummariesResponse,
64
+ params=query_params,
65
+ wrap_response=False,
66
+ )
67
+
68
+ def get_assistants_chats(
69
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
70
+ ) -> TabularResponse:
71
+ """Get assistants chats analytics.
72
+
73
+ Args:
74
+ params: Query parameters (filters + pagination)
75
+
76
+ Returns:
77
+ TabularResponse with assistant performance metrics including chat statistics,
78
+ error rates, token consumption, and costs
79
+ """
80
+ query_params = params.model_dump(exclude_none=True) if params else {}
81
+ return self._api.get(
82
+ "/v1/analytics/assistants-chats",
83
+ TabularResponse,
84
+ params=query_params,
85
+ wrap_response=False,
86
+ )
87
+
88
+ def get_workflows(
89
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
90
+ ) -> TabularResponse:
91
+ """Get workflows analytics.
92
+
93
+ Args:
94
+ params: Query parameters (filters + pagination)
95
+
96
+ Returns:
97
+ TabularResponse with workflow execution metrics including total runs,
98
+ success/failure rates, costs, and performance statistics
99
+ """
100
+ query_params = params.model_dump(exclude_none=True) if params else {}
101
+ return self._api.get(
102
+ "/v1/analytics/workflows",
103
+ TabularResponse,
104
+ params=query_params,
105
+ wrap_response=False,
106
+ )
107
+
108
+ def get_tools_usage(
109
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
110
+ ) -> TabularResponse:
111
+ """Get tool usage analytics.
112
+
113
+ Args:
114
+ params: Query parameters (filters + pagination)
115
+
116
+ Returns:
117
+ TabularResponse with tool usage metrics including invocation counts,
118
+ user adoption, agent usage, and error tracking
119
+ """
120
+ query_params = params.model_dump(exclude_none=True) if params else {}
121
+ return self._api.get(
122
+ "/v1/analytics/tools-usage",
123
+ TabularResponse,
124
+ params=query_params,
125
+ wrap_response=False,
126
+ )
127
+
128
+ def get_webhooks_invocation(
129
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
130
+ ) -> TabularResponse:
131
+ """Get webhooks invocation statistics.
132
+
133
+ Args:
134
+ params: Query parameters (filters + pagination)
135
+
136
+ Returns:
137
+ TabularResponse with webhook usage patterns showing invocation counts
138
+ per user and webhook alias
139
+ """
140
+ query_params = params.model_dump(exclude_none=True) if params else {}
141
+ return self._api.get(
142
+ "/v1/analytics/webhooks-invocation",
143
+ TabularResponse,
144
+ params=query_params,
145
+ wrap_response=False,
146
+ )
147
+
148
+ def get_mcp_servers(
149
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
150
+ ) -> TabularResponse:
151
+ """Get top MCP servers analytics.
152
+
153
+ Args:
154
+ params: Query parameters (filters + pagination)
155
+
156
+ Returns:
157
+ TabularResponse with MCP server usage distribution showing
158
+ percentage share of each server
159
+ """
160
+ query_params = params.model_dump(exclude_none=True) if params else {}
161
+ return self._api.get(
162
+ "/v1/analytics/mcp-servers",
163
+ TabularResponse,
164
+ params=query_params,
165
+ wrap_response=False,
166
+ )
167
+
168
+ def get_mcp_servers_by_users(
169
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
170
+ ) -> TabularResponse:
171
+ """Get MCP servers usage by users.
172
+
173
+ Args:
174
+ params: Query parameters (filters + pagination)
175
+
176
+ Returns:
177
+ TabularResponse with individual user adoption and usage of MCP servers
178
+ showing which users are utilizing which servers
179
+ """
180
+ query_params = params.model_dump(exclude_none=True) if params else {}
181
+ return self._api.get(
182
+ "/v1/analytics/mcp-servers-by-users",
183
+ TabularResponse,
184
+ params=query_params,
185
+ wrap_response=False,
186
+ )
187
+
188
+ def get_projects_spending(
189
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
190
+ ) -> TabularResponse:
191
+ """Get money spent by projects.
192
+
193
+ Args:
194
+ params: Query parameters (filters + pagination)
195
+
196
+ Returns:
197
+ TabularResponse with project-level spending ranked by amount
198
+ """
199
+ query_params = params.model_dump(exclude_none=True) if params else {}
200
+ return self._api.get(
201
+ "/v1/analytics/projects-spending",
202
+ TabularResponse,
203
+ params=query_params,
204
+ wrap_response=False,
205
+ )
206
+
207
+ def get_llms_usage(
208
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
209
+ ) -> TabularResponse:
210
+ """Get top LLMs usage analytics.
211
+
212
+ Args:
213
+ params: Query parameters (filters + pagination)
214
+
215
+ Returns:
216
+ TabularResponse with LLM model usage distribution showing
217
+ preference patterns across different models
218
+ """
219
+ query_params = params.model_dump(exclude_none=True) if params else {}
220
+ return self._api.get(
221
+ "/v1/analytics/llms-usage",
222
+ TabularResponse,
223
+ params=query_params,
224
+ wrap_response=False,
225
+ )
226
+
227
+ def get_users_spending(
228
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
229
+ ) -> TabularResponse:
230
+ """Get money spent by users.
231
+
232
+ Args:
233
+ params: Query parameters (filters + pagination)
234
+
235
+ Returns:
236
+ TabularResponse with individual user spending ranked by amount
237
+ """
238
+ query_params = params.model_dump(exclude_none=True) if params else {}
239
+ return self._api.get(
240
+ "/v1/analytics/users-spending",
241
+ TabularResponse,
242
+ params=query_params,
243
+ wrap_response=False,
244
+ )
245
+
246
+ def get_budget_soft_limit(
247
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
248
+ ) -> TabularResponse:
249
+ """Get soft budget limit violations.
250
+
251
+ Args:
252
+ params: Query parameters (filters + pagination)
253
+
254
+ Returns:
255
+ TabularResponse with users who have exceeded soft budget limits
256
+ (warning threshold)
257
+ """
258
+ query_params = params.model_dump(exclude_none=True) if params else {}
259
+ return self._api.get(
260
+ "/v1/analytics/budget-soft-limit",
261
+ TabularResponse,
262
+ params=query_params,
263
+ wrap_response=False,
264
+ )
265
+
266
+ def get_budget_hard_limit(
267
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
268
+ ) -> TabularResponse:
269
+ """Get hard budget limit violations.
270
+
271
+ Args:
272
+ params: Query parameters (filters + pagination)
273
+
274
+ Returns:
275
+ TabularResponse with users who have reached or exceeded hard budget
276
+ limits (enforcement threshold)
277
+ """
278
+ query_params = params.model_dump(exclude_none=True) if params else {}
279
+ return self._api.get(
280
+ "/v1/analytics/budget-hard-limit",
281
+ TabularResponse,
282
+ params=query_params,
283
+ wrap_response=False,
284
+ )
285
+
286
+ def get_users_activity(
287
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
288
+ ) -> TabularResponse:
289
+ """Get most active users analytics.
290
+
291
+ Args:
292
+ params: Query parameters (filters + pagination)
293
+
294
+ Returns:
295
+ TabularResponse with comprehensive user activity metrics including
296
+ spending, recent projects, and token consumption
297
+ """
298
+ query_params = params.model_dump(exclude_none=True) if params else {}
299
+ return self._api.get(
300
+ "/v1/analytics/users-activity",
301
+ TabularResponse,
302
+ params=query_params,
303
+ wrap_response=False,
304
+ )
305
+
306
+ def get_projects_activity(
307
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
308
+ ) -> TabularResponse:
309
+ """Get most active projects analytics.
310
+
311
+ Args:
312
+ params: Query parameters (filters + pagination)
313
+
314
+ Returns:
315
+ TabularResponse with project activity metrics including spending,
316
+ active user counts, and token consumption
317
+ """
318
+ query_params = params.model_dump(exclude_none=True) if params else {}
319
+ return self._api.get(
320
+ "/v1/analytics/projects-activity",
321
+ TabularResponse,
322
+ params=query_params,
323
+ wrap_response=False,
324
+ )
325
+
326
+ def get_agents_usage(
327
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
328
+ ) -> TabularResponse:
329
+ """Get top agents usage analytics.
330
+
331
+ Args:
332
+ params: Query parameters (filters + pagination)
333
+
334
+ Returns:
335
+ TabularResponse with agent usage analytics including invocations,
336
+ spending, user adoption, tool usage, and error tracking
337
+ """
338
+ query_params = params.model_dump(exclude_none=True) if params else {}
339
+ return self._api.get(
340
+ "/v1/analytics/agents-usage",
341
+ TabularResponse,
342
+ params=query_params,
343
+ wrap_response=False,
344
+ )
345
+
346
+ def get_cli_agents(
347
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
348
+ ) -> TabularResponse:
349
+ """Get top CLI agents analytics.
350
+
351
+ Args:
352
+ params: Query parameters (filters + pagination)
353
+
354
+ Returns:
355
+ TabularResponse with CLI agent usage distribution showing
356
+ percentage share of each agent
357
+ """
358
+ query_params = params.model_dump(exclude_none=True) if params else {}
359
+ return self._api.get(
360
+ "/v1/analytics/cli-agents",
361
+ TabularResponse,
362
+ params=query_params,
363
+ wrap_response=False,
364
+ )
365
+
366
+ def get_cli_llms(
367
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
368
+ ) -> TabularResponse:
369
+ """Get top CLI LLMs analytics.
370
+
371
+ Args:
372
+ params: Query parameters (filters + pagination)
373
+
374
+ Returns:
375
+ TabularResponse with LLM model usage distribution in CLI context
376
+ showing percentage share
377
+ """
378
+ query_params = params.model_dump(exclude_none=True) if params else {}
379
+ return self._api.get(
380
+ "/v1/analytics/cli-llms",
381
+ TabularResponse,
382
+ params=query_params,
383
+ wrap_response=False,
384
+ )
385
+
386
+ def get_cli_users(
387
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
388
+ ) -> TabularResponse:
389
+ """Get most active CLI users analytics.
390
+
391
+ Args:
392
+ params: Query parameters (filters + pagination)
393
+
394
+ Returns:
395
+ TabularResponse with CLI user activity showing total invocation
396
+ counts per user
397
+ """
398
+ query_params = params.model_dump(exclude_none=True) if params else {}
399
+ return self._api.get(
400
+ "/v1/analytics/cli-users",
401
+ TabularResponse,
402
+ params=query_params,
403
+ wrap_response=False,
404
+ )
405
+
406
+ def get_cli_errors(
407
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
408
+ ) -> TabularResponse:
409
+ """Get top error codes for CLI.
410
+
411
+ Args:
412
+ params: Query parameters (filters + pagination)
413
+
414
+ Returns:
415
+ TabularResponse with most common CLI error codes with occurrence
416
+ counts for troubleshooting
417
+ """
418
+ query_params = params.model_dump(exclude_none=True) if params else {}
419
+ return self._api.get(
420
+ "/v1/analytics/cli-errors",
421
+ TabularResponse,
422
+ params=query_params,
423
+ wrap_response=False,
424
+ )
425
+
426
+ def get_cli_repositories(
427
+ self, params: Optional[PaginatedAnalyticsQueryParams] = None
428
+ ) -> TabularResponse:
429
+ """Get repository statistics.
430
+
431
+ Args:
432
+ params: Query parameters (filters + pagination)
433
+
434
+ Returns:
435
+ TabularResponse with repository-level metrics including code changes,
436
+ token consumption, and branch activity
437
+ """
438
+ query_params = params.model_dump(exclude_none=True) if params else {}
439
+ return self._api.get(
440
+ "/v1/analytics/cli-repositories",
441
+ TabularResponse,
442
+ params=query_params,
443
+ wrap_response=False,
444
+ )
445
+
446
+ def get_users(
447
+ self, params: Optional[AnalyticsQueryParams] = None
448
+ ) -> UsersListResponse:
449
+ """Get users list.
450
+
451
+ Args:
452
+ params: Query parameters (time filters, user/project filters)
453
+
454
+ Returns:
455
+ UsersListResponse with list of unique users
456
+ """
457
+ query_params = params.model_dump(exclude_none=True) if params else {}
458
+ return self._api.get(
459
+ "/v1/analytics/users",
460
+ UsersListResponse,
461
+ params=query_params,
462
+ wrap_response=False,
463
+ )
@@ -14,6 +14,8 @@ from ..models.assistant import (
14
14
  Assistant,
15
15
  AssistantCreateRequest,
16
16
  AssistantUpdateRequest,
17
+ AssistantCreateResponse,
18
+ AssistantUpdateResponse,
17
19
  ToolKitDetails,
18
20
  AssistantChatRequest,
19
21
  BaseModelResponse,
@@ -90,20 +92,24 @@ class AssistantService:
90
92
  """
91
93
  return self._api.get(f"/v1/assistants/slug/{slug}", Assistant)
92
94
 
93
- def create(self, request: AssistantCreateRequest) -> dict:
95
+ def create(self, request: AssistantCreateRequest) -> AssistantCreateResponse:
94
96
  """Create a new assistant.
95
97
 
96
98
  Args:
97
99
  request: Assistant creation request
98
100
 
99
101
  Returns:
100
- Created assistant details
102
+ AssistantCreateResponse with assistant_id and optional validation results
101
103
  """
102
104
  return self._api.post(
103
- "/v1/assistants", dict, json_data=request.model_dump(exclude_none=True)
105
+ "/v1/assistants",
106
+ AssistantCreateResponse,
107
+ json_data=request.model_dump(exclude_none=True),
104
108
  )
105
109
 
106
- def update(self, assistant_id: str, request: AssistantUpdateRequest) -> dict:
110
+ def update(
111
+ self, assistant_id: str, request: AssistantUpdateRequest
112
+ ) -> AssistantUpdateResponse:
107
113
  """Update an existing assistant.
108
114
 
109
115
  Args:
@@ -111,11 +117,11 @@ class AssistantService:
111
117
  request: Assistant update request
112
118
 
113
119
  Returns:
114
- Updated assistant details
120
+ AssistantUpdateResponse with optional validation results
115
121
  """
116
122
  return self._api.put(
117
123
  f"/v1/assistants/{assistant_id}",
118
- dict,
124
+ AssistantUpdateResponse,
119
125
  json_data=request.model_dump(exclude_none=True),
120
126
  )
121
127
 
@@ -296,7 +302,8 @@ class AssistantService:
296
302
  if hasattr(version, "assistant_ids")
297
303
  else assistant.assistant_ids,
298
304
  )
299
- resp = self.update(assistant_id, update_req)
305
+ update_resp = self.update(assistant_id, update_req)
306
+ resp = update_resp.model_dump()
300
307
  resp["_rollback_fallback"] = True
301
308
  resp["_target_version"] = version_number
302
309
  if change_notes:
@@ -0,0 +1,76 @@
1
+ """CodeMie guardrail service implementation for managing guardrail assignments."""
2
+
3
+ from ..models.guardrails import (
4
+ GuardrailAssignmentRequest,
5
+ GuardrailAssignmentResponse,
6
+ )
7
+ from ..utils import ApiRequestHandler
8
+
9
+
10
+ class CodemieGuardrailService:
11
+ """Service for managing CodeMie guardrail assignments."""
12
+
13
+ def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
14
+ """Initialize the CodeMie guardrail service.
15
+
16
+ Args:
17
+ api_domain: Base URL for the CodeMie API
18
+ token: Authentication token
19
+ verify_ssl: Whether to verify SSL certificates
20
+ """
21
+ self._api = ApiRequestHandler(api_domain, token, verify_ssl)
22
+
23
+ def assign_guardrails(
24
+ self,
25
+ guardrail_id: str,
26
+ assignment: GuardrailAssignmentRequest,
27
+ ) -> GuardrailAssignmentResponse:
28
+ """Assign guardrails to project entities (assistants, workflows, datasources).
29
+
30
+ Args:
31
+ guardrail_id: ID of the guardrail to assign (AI run ID from installation)
32
+ assignment: Assignment configuration for different entity types
33
+
34
+ Returns:
35
+ GuardrailAssignmentResponse with success status
36
+
37
+ Example:
38
+ >>> from codemie_sdk.models.guardrails import (
39
+ ... GuardrailAssignmentRequest,
40
+ ... GuardrailAssignmentEntity,
41
+ ... GuardrailAssignmentSetting
42
+ ... )
43
+ >>> # Assign guardrail to all project assistants
44
+ >>> assignment = GuardrailAssignmentRequest(
45
+ ... assistants=GuardrailAssignmentEntity(
46
+ ... settings=[GuardrailAssignmentSetting(mode="all", source="input")],
47
+ ... items=[]
48
+ ... )
49
+ ... )
50
+ >>> response = client.codemie_guardrails.assign_guardrails(
51
+ ... guardrail_id="ai_run_123",
52
+ ... assignment=assignment
53
+ ... )
54
+ >>> if response.success:
55
+ ... print("Guardrail assigned successfully!")
56
+ >>>
57
+ >>> # Assign to specific assistants
58
+ >>> assignment = GuardrailAssignmentRequest(
59
+ ... assistants=GuardrailAssignmentEntity(
60
+ ... settings=[],
61
+ ... items=["asst_123", "asst_456"]
62
+ ... )
63
+ ... )
64
+ >>> response = client.codemie_guardrails.assign_guardrails(
65
+ ... guardrail_id="ai_run_123",
66
+ ... assignment=assignment
67
+ ... )
68
+ """
69
+ payload = assignment.model_dump(by_alias=True)
70
+
71
+ return self._api.put(
72
+ f"/v1/guardrails/{guardrail_id}/assignments",
73
+ GuardrailAssignmentResponse,
74
+ json_data=payload,
75
+ wrap_response=False,
76
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codemie-sdk-python
3
- Version: 0.1.273
3
+ Version: 0.1.289
4
4
  Summary: CodeMie SDK for Python
5
5
  Author: Vadym Vlasenko
6
6
  Author-email: vadym_vlasenko@epam.com
@@ -1,15 +1,18 @@
1
- codemie_sdk/__init__.py,sha256=rdb72JEOkNMYrVYgnahqFpp7I6FgbmeWuNflMKWetgE,4168
1
+ codemie_sdk/__init__.py,sha256=4ha4xbTsassZHl3AsbIM6rEF3wfl0h2e0YcZiAOZb7Q,5258
2
2
  codemie_sdk/auth/__init__.py,sha256=IksEj223xEZtJ-cQ0AT9L0Bs9psIJ8QNzDXrPTUQ3xQ,126
3
3
  codemie_sdk/auth/credentials.py,sha256=OzR_CXPBNTEC6VmNdzcCHF7rWWGrVf3agAlGKgPtTiU,4361
4
4
  codemie_sdk/client/__init__.py,sha256=yf6C39MmrJ6gK9ZHMhBeynKwUUYVSUTQbKxU8-4qpKg,101
5
- codemie_sdk/client/client.py,sha256=sz6h62XE1g2tTbgNdbeMws-wQPROXwLTUmtaVI6TC1U,7155
5
+ codemie_sdk/client/client.py,sha256=SV-wo892o3YlvaGcLL9Cx0mDFggBZFBsxCVfZwjnokI,8039
6
6
  codemie_sdk/exceptions.py,sha256=XoVPyognx-JmyVxLHkZPAcX1CMi1OoT1diBFJLU54so,1183
7
7
  codemie_sdk/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- codemie_sdk/models/assistant.py,sha256=PO2TMB9koJzrMEZ0jWtR3MVwyU88hebNYLjD3RB1uro,12736
8
+ codemie_sdk/models/admin.py,sha256=eAsz4rFFrXCXjUubn4U23AmhZA5bAT0ip5RyfyEc5e0,805
9
+ codemie_sdk/models/analytics.py,sha256=mquZwaIwouQMAXEDy0E5ClvmIFz7rtTcgu-OzVhTMn4,5008
10
+ codemie_sdk/models/assistant.py,sha256=KJ1bgDKRnur_O1XNlE__Um-mI_zG_LLO2WLDUlL9VQw,15907
9
11
  codemie_sdk/models/common.py,sha256=gmZ-ps8TbaieNKr0kUKoQEjhVrHD2CAYomOpZQRatH8,1195
10
12
  codemie_sdk/models/conversation.py,sha256=tGlqtVnoRCbTm8J8Y1BUmBvMpLW3IRFE0CIHJYoNU_Y,4238
11
13
  codemie_sdk/models/datasource.py,sha256=rL1pUkdPq7_KmnuPkSCO9Bp7DlAXCN51YrtbP3os3qM,13843
12
14
  codemie_sdk/models/file_operation.py,sha256=D2hnsxOO9lzVMw0BNCgKPfHf28bWQmbw5rccgaTXI90,747
15
+ codemie_sdk/models/guardrails.py,sha256=6AyN0kx8lII85jFwLQztdCZJ2nPpjAoI6PU2f3TP7RM,2139
13
16
  codemie_sdk/models/integration.py,sha256=FFFcggLf9kh5QVle1T8Jexyh5bc3hgh39YHIp8xfMZ0,2328
14
17
  codemie_sdk/models/llm.py,sha256=ppb9-1dx1UFhRuJpSR3ij7H6Pfhe9nO4C4BEOIbToy4,1192
15
18
  codemie_sdk/models/task.py,sha256=J4ZFRY3s8qBGrqB5NLQF0rMbInLh4s7OEZ0ZfmnW0Ho,1476
@@ -22,7 +25,10 @@ codemie_sdk/models/workflow.py,sha256=qfk0rBJnFUMpcEDq_E5GB3hzYKbe_bb2NYJlLZJwUE
22
25
  codemie_sdk/models/workflow_execution_payload.py,sha256=Pa28ElqsJLudscJnmZhXUEJWJXLw55xc-KYBPi97EZ4,724
23
26
  codemie_sdk/models/workflow_state.py,sha256=okEMKzkiBU3GHs9VNBoiEMOnOeZRMXGYtpL0NYSg-FY,1374
24
27
  codemie_sdk/models/workflow_thoughts.py,sha256=CjHaIPgca9kQAjpoq8IpX4MuDeql1SvaoKS5RmyU2SE,616
25
- codemie_sdk/services/assistant.py,sha256=hbKW2gweGMcOQCXbhrkgI__gwuPgZk0jz1GzJ7kH8Dw,15940
28
+ codemie_sdk/services/admin.py,sha256=j_d_LuHHC70ckIz1ImqwccQIk1Ew05_Hl0-lw6meWVA,1723
29
+ codemie_sdk/services/analytics.py,sha256=A7J-cC-82vD1m8bLYX3Nyz5MdpveuMT61-M_827f52A,14956
30
+ codemie_sdk/services/assistant.py,sha256=GIiD_t-g1dJnuNmZOQZlr4020hse0NIBE1mULQS_65k,16247
31
+ codemie_sdk/services/codemie_guardrails.py,sha256=VI4dqoswYAQMHCgTsJds7Uugq0zk9TPSdKzt6keSyQQ,2812
26
32
  codemie_sdk/services/conversation.py,sha256=Ss0mkGaBi4u8-YKzhRYUJOfoFqJueDp9JurI5DRCGT8,2566
27
33
  codemie_sdk/services/datasource.py,sha256=vusKiIyRZwliBUPzp78saXuiIEAg1f4FLz-g5ildRFY,9773
28
34
  codemie_sdk/services/files.py,sha256=SgqPmI1jnWIQ7pdxZSaRDnCFU7OnJllb5XLH-1q3zNg,2512
@@ -40,6 +46,6 @@ codemie_sdk/services/workflow_execution.py,sha256=BfbnoyMutQ4_SkpKdCi-F2A5r9JqEf
40
46
  codemie_sdk/services/workflow_execution_state.py,sha256=tXoaa8yT09xgYEUNiHhVULe76TwGwVgZupMIUyyLxdo,2070
41
47
  codemie_sdk/utils/__init__.py,sha256=BXAJJfAzO89-kMYvWWo9wSNhSbGgF3vB1In9sePFhMM,109
42
48
  codemie_sdk/utils/http.py,sha256=pVNYH1PTqfu8ZzP3tBCugVUOroh_QcKu2ej8EzeDm4Q,10337
43
- codemie_sdk_python-0.1.273.dist-info/METADATA,sha256=xW64JMVO5j4kmOag-CUJ3VKX1pzobiCNEF5GqsL43Dg,36787
44
- codemie_sdk_python-0.1.273.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
45
- codemie_sdk_python-0.1.273.dist-info/RECORD,,
49
+ codemie_sdk_python-0.1.289.dist-info/METADATA,sha256=GnMMB5-Ho8ArDwv2VrRfH38nk4CN7x6Kb1MaulAi4vo,36787
50
+ codemie_sdk_python-0.1.289.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
51
+ codemie_sdk_python-0.1.289.dist-info/RECORD,,