codemie-sdk-python 0.1.427__tar.gz → 0.1.428__tar.gz

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.
Files changed (61) hide show
  1. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/PKG-INFO +1 -1
  2. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/pyproject.toml +1 -1
  3. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/auth/credentials.py +35 -19
  4. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/client/client.py +32 -83
  5. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/admin.py +2 -2
  6. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/analytics.py +2 -2
  7. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/assistant.py +7 -3
  8. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/categories.py +2 -2
  9. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/codemie_guardrails.py +2 -2
  10. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/conversation.py +2 -2
  11. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/datasource.py +2 -2
  12. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/files.py +2 -2
  13. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/integration.py +2 -2
  14. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/llm.py +2 -2
  15. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/mermaid.py +2 -2
  16. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/project.py +2 -2
  17. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/skill.py +2 -2
  18. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/task.py +2 -2
  19. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/user.py +2 -2
  20. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/vendor_assistant.py +2 -2
  21. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/vendor_guardrail.py +2 -2
  22. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/vendor_knowledgebase.py +2 -2
  23. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/vendor_workflow.py +2 -2
  24. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/webhook.py +2 -2
  25. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/workflow.py +2 -2
  26. codemie_sdk_python-0.1.428/src/codemie_sdk/utils/__init__.py +5 -0
  27. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/utils/http.py +26 -8
  28. codemie_sdk_python-0.1.427/src/codemie_sdk/utils/__init__.py +0 -5
  29. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/README.md +0 -0
  30. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/__init__.py +0 -0
  31. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/auth/__init__.py +0 -0
  32. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/client/__init__.py +0 -0
  33. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/exceptions.py +0 -0
  34. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/__init__.py +0 -0
  35. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/admin.py +0 -0
  36. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/analytics.py +0 -0
  37. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/assistant.py +0 -0
  38. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/categories.py +0 -0
  39. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/common.py +0 -0
  40. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/conversation.py +0 -0
  41. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/datasource.py +0 -0
  42. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/errors.py +0 -0
  43. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/file_operation.py +0 -0
  44. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/guardrails.py +0 -0
  45. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/integration.py +0 -0
  46. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/llm.py +0 -0
  47. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/mermaid.py +0 -0
  48. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/project.py +0 -0
  49. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/skill.py +0 -0
  50. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/task.py +0 -0
  51. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/user.py +0 -0
  52. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/vendor_assistant.py +0 -0
  53. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/vendor_guardrail.py +0 -0
  54. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/vendor_knowledgebase.py +0 -0
  55. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/vendor_workflow.py +0 -0
  56. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/workflow.py +0 -0
  57. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/workflow_execution_payload.py +0 -0
  58. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/workflow_state.py +0 -0
  59. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/models/workflow_thoughts.py +0 -0
  60. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/workflow_execution.py +0 -0
  61. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.428}/src/codemie_sdk/services/workflow_execution_state.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codemie-sdk-python
3
- Version: 0.1.427
3
+ Version: 0.1.428
4
4
  Summary: CodeMie SDK for Python
5
5
  Author: Vadym Vlasenko
6
6
  Author-email: vadym_vlasenko@epam.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "codemie-sdk-python"
3
- version = "0.1.427"
3
+ version = "0.1.428"
4
4
  description = "CodeMie SDK for Python"
5
5
  authors = [
6
6
  "Vadym Vlasenko <vadym_vlasenko@epam.com>",
@@ -1,12 +1,15 @@
1
1
  """Authentication credentials module for CodeMie SDK."""
2
2
 
3
+ import time
3
4
  import requests
4
- from typing import Optional
5
+ from typing import Callable, Optional, Union
5
6
 
6
7
 
7
8
  class KeycloakCredentials:
8
9
  """Keycloak authentication credentials handler."""
9
10
 
11
+ _TOKEN_EXPIRY_BUFFER_SECONDS = 30
12
+
10
13
  def __init__(
11
14
  self,
12
15
  server_url: str,
@@ -15,7 +18,7 @@ class KeycloakCredentials:
15
18
  client_secret: Optional[str] = None,
16
19
  username: Optional[str] = None,
17
20
  password: Optional[str] = None,
18
- external_token: Optional[str] = None,
21
+ external_token: Optional[Union[str, Callable[[], str]]] = None,
19
22
  external_idp: Optional[str] = None,
20
23
  verify_ssl: bool = True,
21
24
  ):
@@ -41,9 +44,15 @@ class KeycloakCredentials:
41
44
  self.external_token = external_token
42
45
  self.external_idp = external_idp
43
46
  self.verify_ssl = verify_ssl
47
+ self._cached_token: Optional[str] = None
48
+ self._token_expires_at: float = 0.0
44
49
 
45
50
  def get_token(self) -> str:
46
- """Get access token using either client credentials or password grant."""
51
+ """Get access token, returning cached value if still valid."""
52
+ now = time.monotonic()
53
+ if self._cached_token and now < self._token_expires_at:
54
+ return self._cached_token
55
+
47
56
  if not (
48
57
  (self.client_id and self.client_secret)
49
58
  or (self.username and self.password)
@@ -57,28 +66,31 @@ class KeycloakCredentials:
57
66
  f"{self.server_url}/realms/{self.realm_name}/protocol/openid-connect/token"
58
67
  )
59
68
 
60
- if self.username and self.password:
61
- # Use Resource Owner Password Credentials flow
62
- payload = {
63
- "grant_type": "password",
64
- "username": self.username,
65
- "password": self.password,
66
- "client_id": self.client_id
67
- or "codemie-sdk", # Use default client if not specified
68
- }
69
- if self.client_secret:
70
- payload["client_secret"] = self.client_secret
71
- elif self.external_token and self.external_idp:
69
+ if self.external_token and self.external_idp:
70
+ subject_token = (
71
+ self.external_token()
72
+ if callable(self.external_token)
73
+ else self.external_token
74
+ )
72
75
  payload = {
73
76
  "client_id": self.client_id,
74
77
  "client_secret": self.client_secret,
75
78
  "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
76
- "subject_token": self.external_token,
79
+ "subject_token": subject_token,
80
+ "subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
77
81
  "subject_issuer": self.external_idp,
78
82
  "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
79
83
  }
84
+ elif self.username and self.password:
85
+ payload = {
86
+ "grant_type": "password",
87
+ "username": self.username,
88
+ "password": self.password,
89
+ "client_id": self.client_id or "codemie-sdk",
90
+ }
91
+ if self.client_secret:
92
+ payload["client_secret"] = self.client_secret
80
93
  else:
81
- # Use Client Credentials flow
82
94
  payload = {
83
95
  "grant_type": "client_credentials",
84
96
  "client_id": self.client_id,
@@ -87,7 +99,11 @@ class KeycloakCredentials:
87
99
 
88
100
  response = requests.post(url, data=payload, verify=self.verify_ssl)
89
101
  response.raise_for_status()
90
- return response.json()["access_token"]
102
+ data = response.json()
103
+ self._cached_token = data["access_token"]
104
+ expires_in = data.get("expires_in", 300)
105
+ self._token_expires_at = now + expires_in - self._TOKEN_EXPIRY_BUFFER_SECONDS
106
+ return self._cached_token
91
107
 
92
108
  def exchange_token_for_user(self, email: str, access_token: str) -> str:
93
109
  """Exchange service account token for user token."""
@@ -118,7 +134,7 @@ class KeycloakCredentials:
118
134
  payload = {
119
135
  "client_id": self.client_id,
120
136
  "client_secret": self.client_secret,
121
- "grant_type": "urn:ietf:params:oauth:grant-datasource_type:token-exchange",
137
+ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
122
138
  "subject_token": service_account_token,
123
139
  "requested_subject": user_id,
124
140
  }
@@ -78,62 +78,68 @@ class CodeMieClient:
78
78
 
79
79
  requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
80
80
 
81
- # Initialize token
81
+ # Initialize token; keep string copy for backward-compat callers reading _token directly
82
82
  self._token = "" if self._is_localhost else self.auth.get_token()
83
+ # Services receive the bound method so each request resolves a fresh (cached) token
84
+ _token_source = "" if self._is_localhost else self.auth.get_token
83
85
 
84
86
  # Initialize services with verify_ssl parameter and token
85
- self.admin = AdminService(self._api_domain, self._token, verify_ssl=verify_ssl)
87
+ self.admin = AdminService(
88
+ self._api_domain, _token_source, verify_ssl=verify_ssl
89
+ )
86
90
  self.analytics = AnalyticsService(
87
- self._api_domain, self._token, verify_ssl=verify_ssl
91
+ self._api_domain, _token_source, verify_ssl=verify_ssl
88
92
  )
89
93
  self.assistants = AssistantService(
90
- self._api_domain, self._token, verify_ssl=verify_ssl
94
+ self._api_domain, _token_source, verify_ssl=verify_ssl
91
95
  )
92
96
  self.categories = CategoryService(
93
- self._api_domain, self._token, verify_ssl=verify_ssl
97
+ self._api_domain, _token_source, verify_ssl=verify_ssl
94
98
  )
95
- self.llms = LLMService(self._api_domain, self._token, verify_ssl=verify_ssl)
99
+ self.llms = LLMService(self._api_domain, _token_source, verify_ssl=verify_ssl)
96
100
  self.mermaid = MermaidService(
97
- self._api_domain, self._token, verify_ssl=verify_ssl
101
+ self._api_domain, _token_source, verify_ssl=verify_ssl
98
102
  )
99
103
  self.integrations = IntegrationService(
100
- self._api_domain, self._token, verify_ssl=verify_ssl
104
+ self._api_domain, _token_source, verify_ssl=verify_ssl
101
105
  )
102
106
  self.projects = ProjectService(
103
- self._api_domain, self._token, verify_ssl=verify_ssl
107
+ self._api_domain, _token_source, verify_ssl=verify_ssl
108
+ )
109
+ self.skills = SkillService(
110
+ self._api_domain, _token_source, verify_ssl=verify_ssl
104
111
  )
105
- self.skills = SkillService(self._api_domain, self._token, verify_ssl=verify_ssl)
106
- self.tasks = TaskService(self._api_domain, self._token, verify_ssl=verify_ssl)
107
- self.users = UserService(self._api_domain, self._token, verify_ssl=verify_ssl)
112
+ self.tasks = TaskService(self._api_domain, _token_source, verify_ssl=verify_ssl)
113
+ self.users = UserService(self._api_domain, _token_source, verify_ssl=verify_ssl)
108
114
  self.datasources = DatasourceService(
109
- self._api_domain, self._token, verify_ssl=verify_ssl
115
+ self._api_domain, _token_source, verify_ssl=verify_ssl
110
116
  )
111
117
  self.workflows = WorkflowService(
112
- self._api_domain, self._token, verify_ssl=self._verify_ssl
118
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
113
119
  )
114
120
  self.conversations = ConversationService(
115
- self._api_domain, self._token, verify_ssl=self._verify_ssl
121
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
116
122
  )
117
123
  self.files = FileOperationService(
118
- self._api_domain, self._token, verify_ssl=self._verify_ssl
124
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
119
125
  )
120
126
  self.webhook = WebhookService(
121
- self._api_domain, self._token, verify_ssl=self._verify_ssl
127
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
122
128
  )
123
129
  self.vendor_assistants = VendorAssistantService(
124
- self._api_domain, self._token, verify_ssl=self._verify_ssl
130
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
125
131
  )
126
132
  self.vendor_workflows = VendorWorkflowService(
127
- self._api_domain, self._token, verify_ssl=self._verify_ssl
133
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
128
134
  )
129
135
  self.vendor_knowledgebases = VendorKnowledgeBaseService(
130
- self._api_domain, self._token, verify_ssl=self._verify_ssl
136
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
131
137
  )
132
138
  self.vendor_guardrails = VendorGuardrailService(
133
- self._api_domain, self._token, verify_ssl=self._verify_ssl
139
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
134
140
  )
135
141
  self.codemie_guardrails = CodemieGuardrailService(
136
- self._api_domain, self._token, verify_ssl=self._verify_ssl
142
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
137
143
  )
138
144
 
139
145
  @property
@@ -156,66 +162,9 @@ class CodeMieClient:
156
162
 
157
163
  def refresh_token(self) -> str:
158
164
  """Force token refresh."""
165
+ # Invalidate cache so next get_token() call re-fetches from Keycloak
166
+ self.auth._cached_token = None
167
+ self.auth._token_expires_at = 0.0
159
168
  self._token = "" if self._is_localhost else self.auth.get_token()
160
- # Update token in services
161
- self.admin = AdminService(
162
- self._api_domain, self._token, verify_ssl=self._verify_ssl
163
- )
164
- self.analytics = AnalyticsService(
165
- self._api_domain, self._token, verify_ssl=self._verify_ssl
166
- )
167
- self.assistants = AssistantService(
168
- self._api_domain, self._token, verify_ssl=self._verify_ssl
169
- )
170
- self.categories = CategoryService(
171
- self._api_domain, self._token, verify_ssl=self._verify_ssl
172
- )
173
- self.llms = LLMService(
174
- self._api_domain, self._token, verify_ssl=self._verify_ssl
175
- )
176
- self.mermaid = MermaidService(
177
- self._api_domain, self._token, verify_ssl=self._verify_ssl
178
- )
179
- self.integrations = IntegrationService(
180
- self._api_domain, self._token, verify_ssl=self._verify_ssl
181
- )
182
- self.skills = SkillService(
183
- self._api_domain, self._token, verify_ssl=self._verify_ssl
184
- )
185
- self.tasks = TaskService(
186
- self._api_domain, self._token, verify_ssl=self._verify_ssl
187
- )
188
- self.users = UserService(
189
- self._api_domain, self._token, verify_ssl=self._verify_ssl
190
- )
191
- self.datasources = DatasourceService(
192
- self._api_domain, self._token, verify_ssl=self._verify_ssl
193
- )
194
- self.workflows = WorkflowService(
195
- self._api_domain, self._token, verify_ssl=self._verify_ssl
196
- )
197
- self.conversations = ConversationService(
198
- self._api_domain, self._token, verify_ssl=self._verify_ssl
199
- )
200
- self.files = FileOperationService(
201
- self._api_domain, self._token, verify_ssl=self._verify_ssl
202
- )
203
- self.webhook = WebhookService(
204
- self._api_domain, self._token, verify_ssl=self._verify_ssl
205
- )
206
- self.vendor_assistants = VendorAssistantService(
207
- self._api_domain, self._token, verify_ssl=self._verify_ssl
208
- )
209
- self.vendor_workflows = VendorWorkflowService(
210
- self._api_domain, self._token, verify_ssl=self._verify_ssl
211
- )
212
- self.vendor_knowledgebases = VendorKnowledgeBaseService(
213
- self._api_domain, self._token, verify_ssl=self._verify_ssl
214
- )
215
- self.vendor_guardrails = VendorGuardrailService(
216
- self._api_domain, self._token, verify_ssl=self._verify_ssl
217
- )
218
- self.codemie_guardrails = CodemieGuardrailService(
219
- self._api_domain, self._token, verify_ssl=self._verify_ssl
220
- )
169
+ # Services already hold self.auth.get_token callable, so no reconstruction needed
221
170
  return self._token
@@ -7,13 +7,13 @@ from ..models.admin import (
7
7
  ApplicationCreateRequest,
8
8
  ApplicationCreateResponse,
9
9
  )
10
- from ..utils import ApiRequestHandler
10
+ from ..utils import ApiRequestHandler, TokenSource
11
11
 
12
12
 
13
13
  class AdminService:
14
14
  """Service for managing CodeMie applications/projects."""
15
15
 
16
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
16
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
17
17
  """Initialize the admin service.
18
18
 
19
19
  Args:
@@ -9,13 +9,13 @@ from ..models.analytics import (
9
9
  TabularResponse,
10
10
  UsersListResponse,
11
11
  )
12
- from ..utils import ApiRequestHandler
12
+ from ..utils import ApiRequestHandler, TokenSource
13
13
 
14
14
 
15
15
  class AnalyticsService:
16
16
  """Service for managing CodeMie analytics."""
17
17
 
18
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
18
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
19
19
  """Initialize the analytics service.
20
20
 
21
21
  Args:
@@ -26,13 +26,13 @@ from ..models.assistant import (
26
26
  ReactionRequest,
27
27
  )
28
28
  from ..models.common import PaginationParams
29
- from ..utils import ApiRequestHandler
29
+ from ..utils import ApiRequestHandler, TokenSource
30
30
 
31
31
 
32
32
  class AssistantService:
33
33
  """Service for managing CodeMie assistants."""
34
34
 
35
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
35
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
36
36
  """Initialize the assistant service.
37
37
 
38
38
  Args:
@@ -373,7 +373,11 @@ class AssistantService:
373
373
  Chat response or streaming response
374
374
  """
375
375
  pydantic_schema = None
376
- if issubclass(request.output_schema, BaseModel):
376
+ if (
377
+ request.output_schema is not None
378
+ and inspect.isclass(request.output_schema)
379
+ and issubclass(request.output_schema, BaseModel)
380
+ ):
377
381
  pydantic_schema = deepcopy(request.output_schema)
378
382
  request.output_schema = request.output_schema.model_json_schema()
379
383
 
@@ -9,13 +9,13 @@ from ..models.categories import (
9
9
  CategoryResponse,
10
10
  CategoryListResponse,
11
11
  )
12
- from ..utils import ApiRequestHandler
12
+ from ..utils import ApiRequestHandler, TokenSource
13
13
 
14
14
 
15
15
  class CategoryService:
16
16
  """Service for managing CodeMie assistant categories."""
17
17
 
18
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
18
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
19
19
  """Initialize the category service.
20
20
 
21
21
  Args:
@@ -4,13 +4,13 @@ from ..models.guardrails import (
4
4
  GuardrailAssignmentRequest,
5
5
  GuardrailAssignmentResponse,
6
6
  )
7
- from ..utils import ApiRequestHandler
7
+ from ..utils import ApiRequestHandler, TokenSource
8
8
 
9
9
 
10
10
  class CodemieGuardrailService:
11
11
  """Service for managing CodeMie guardrail assignments."""
12
12
 
13
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
13
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
14
14
  """Initialize the CodeMie guardrail service.
15
15
 
16
16
  Args:
@@ -19,13 +19,13 @@ from ..models.conversation import (
19
19
  SharedConversationResponse,
20
20
  )
21
21
  from ..models.assistant import AssistantChatRequest
22
- from ..utils import ApiRequestHandler
22
+ from ..utils import ApiRequestHandler, TokenSource
23
23
 
24
24
 
25
25
  class ConversationService:
26
26
  """Service for managing user conversations."""
27
27
 
28
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
28
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
29
29
  """Initialize the conversation service.
30
30
 
31
31
  Args:
@@ -20,13 +20,13 @@ from ..models.datasource import (
20
20
  ElasticsearchStatsResponse,
21
21
  )
22
22
  from ..models.assistant import AssistantListResponse
23
- from ..utils import ApiRequestHandler
23
+ from ..utils import ApiRequestHandler, TokenSource
24
24
 
25
25
 
26
26
  class DatasourceService:
27
27
  """Service for managing CodeMie Datasources."""
28
28
 
29
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
29
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
30
30
  """Initialize the datasource service.
31
31
 
32
32
  Args:
@@ -5,13 +5,13 @@ from pathlib import Path
5
5
  from typing import List
6
6
 
7
7
  from ..models.file_operation import FileBulkCreateResponse
8
- from ..utils import ApiRequestHandler
8
+ from ..utils import ApiRequestHandler, TokenSource
9
9
 
10
10
 
11
11
  class FileOperationService:
12
12
  """Service for managing file operations."""
13
13
 
14
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
14
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
15
15
  """Initialize the file operation service.
16
16
 
17
17
  Args:
@@ -10,13 +10,13 @@ from ..models.integration import (
10
10
  IntegrationType,
11
11
  IntegrationTestRequest,
12
12
  )
13
- from ..utils import ApiRequestHandler
13
+ from ..utils import ApiRequestHandler, TokenSource
14
14
 
15
15
 
16
16
  class IntegrationService:
17
17
  """Service for managing CodeMie integrations (both user and project settings)."""
18
18
 
19
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
19
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
20
20
  """Initialize the integration service.
21
21
 
22
22
  Args:
@@ -3,13 +3,13 @@
3
3
  from typing import List
4
4
 
5
5
  from ..models.llm import LLMModel
6
- from ..utils.http import ApiRequestHandler
6
+ from ..utils.http import ApiRequestHandler, TokenSource
7
7
 
8
8
 
9
9
  class LLMService:
10
10
  """Service for managing LLM models."""
11
11
 
12
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
12
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
13
13
  """Initialize the LLM models service.
14
14
 
15
15
  Args:
@@ -9,13 +9,13 @@ from ..models.mermaid import (
9
9
  ContentType,
10
10
  ResponseType,
11
11
  )
12
- from ..utils import ApiRequestHandler
12
+ from ..utils import ApiRequestHandler, TokenSource
13
13
 
14
14
 
15
15
  class MermaidService:
16
16
  """Service for generating mermaid diagrams."""
17
17
 
18
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
18
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
19
19
  """Initialize the mermaid service.
20
20
 
21
21
  Args:
@@ -33,13 +33,13 @@ from ..models.project import (
33
33
  ProjectUpdateRequest,
34
34
  ProjectUpdateResponse,
35
35
  )
36
- from ..utils.http import ApiRequestHandler
36
+ from ..utils.http import ApiRequestHandler, TokenSource
37
37
 
38
38
 
39
39
  class ProjectService:
40
40
  """Service for managing projects in CodeMie."""
41
41
 
42
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
42
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
43
43
  """Initialize the ProjectService.
44
44
 
45
45
  Args:
@@ -14,13 +14,13 @@ from ..models.skill import (
14
14
  SkillListResponse,
15
15
  SkillUpdateRequest,
16
16
  )
17
- from ..utils.http import ApiRequestHandler
17
+ from ..utils.http import ApiRequestHandler, TokenSource
18
18
 
19
19
 
20
20
  class SkillService:
21
21
  """Service for managing CodeMie skills."""
22
22
 
23
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
23
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
24
24
  """Initialize the skill service.
25
25
 
26
26
  Args:
@@ -1,13 +1,13 @@
1
1
  """Task service implementation."""
2
2
 
3
3
  from ..models.task import BackgroundTaskEntity
4
- from ..utils.http import ApiRequestHandler
4
+ from ..utils.http import ApiRequestHandler, TokenSource
5
5
 
6
6
 
7
7
  class TaskService:
8
8
  """Service for managing background tasks."""
9
9
 
10
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
10
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
11
11
  """Initialize the Task service.
12
12
 
13
13
  Args:
@@ -1,13 +1,13 @@
1
1
  """User service implementation."""
2
2
 
3
3
  from ..models.user import User, UserData
4
- from ..utils.http import ApiRequestHandler
4
+ from ..utils.http import ApiRequestHandler, TokenSource
5
5
 
6
6
 
7
7
  class UserService:
8
8
  """Service for managing user profile and preferences."""
9
9
 
10
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
10
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
11
11
  """Initialize the User service.
12
12
 
13
13
  Args:
@@ -13,13 +13,13 @@ from ..models.vendor_assistant import (
13
13
  VendorAssistantInstallResponse,
14
14
  VendorAssistantUninstallResponse,
15
15
  )
16
- from ..utils import ApiRequestHandler
16
+ from ..utils import ApiRequestHandler, TokenSource
17
17
 
18
18
 
19
19
  class VendorAssistantService:
20
20
  """Service for managing cloud vendor assistant settings (AWS, Azure, GCP)."""
21
21
 
22
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
22
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
23
23
  """Initialize the vendor service.
24
24
 
25
25
  Args:
@@ -13,13 +13,13 @@ from ..models.vendor_guardrail import (
13
13
  VendorGuardrailInstallResponse,
14
14
  VendorGuardrailUninstallResponse,
15
15
  )
16
- from ..utils import ApiRequestHandler
16
+ from ..utils import ApiRequestHandler, TokenSource
17
17
 
18
18
 
19
19
  class VendorGuardrailService:
20
20
  """Service for managing cloud vendor guardrail settings (AWS, Azure, GCP)."""
21
21
 
22
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
22
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
23
23
  """Initialize the vendor guardrail service.
24
24
 
25
25
  Args:
@@ -11,13 +11,13 @@ from ..models.vendor_knowledgebase import (
11
11
  VendorKnowledgeBaseInstallResponse,
12
12
  VendorKnowledgeBaseUninstallResponse,
13
13
  )
14
- from ..utils import ApiRequestHandler
14
+ from ..utils import ApiRequestHandler, TokenSource
15
15
 
16
16
 
17
17
  class VendorKnowledgeBaseService:
18
18
  """Service for managing cloud vendor knowledge base settings (AWS, Azure, GCP)."""
19
19
 
20
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
20
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
21
21
  """Initialize the vendor knowledge base service.
22
22
 
23
23
  Args:
@@ -12,13 +12,13 @@ from ..models.vendor_workflow import (
12
12
  VendorWorkflowInstallResponse,
13
13
  VendorWorkflowUninstallResponse,
14
14
  )
15
- from ..utils import ApiRequestHandler
15
+ from ..utils import ApiRequestHandler, TokenSource
16
16
 
17
17
 
18
18
  class VendorWorkflowService:
19
19
  """Service for managing cloud vendor workflow settings (AWS, Azure, GCP)."""
20
20
 
21
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
21
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
22
22
  """Initialize the vendor workflow service.
23
23
 
24
24
  Args:
@@ -1,13 +1,13 @@
1
1
  import requests
2
2
 
3
3
  from typing import Dict, Any
4
- from ..utils import ApiRequestHandler
4
+ from ..utils import ApiRequestHandler, TokenSource
5
5
 
6
6
 
7
7
  class WebhookService:
8
8
  """Webhook service implementation."""
9
9
 
10
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
10
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
11
11
  """Initialize the conversation service.
12
12
 
13
13
  Args:
@@ -10,13 +10,13 @@ from ..models.workflow import (
10
10
  WorkflowUpdateRequest,
11
11
  Workflow,
12
12
  )
13
- from ..utils import ApiRequestHandler
13
+ from ..utils import ApiRequestHandler, TokenSource
14
14
 
15
15
 
16
16
  class WorkflowService:
17
17
  """Service for managing CodeMie workflows."""
18
18
 
19
- def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
19
+ def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
20
20
  """Initialize the workflow service.
21
21
 
22
22
  Args:
@@ -0,0 +1,5 @@
1
+ """Utility modules for CodeMie SDK."""
2
+
3
+ from .http import ApiRequestHandler, TokenSource
4
+
5
+ __all__ = ["ApiRequestHandler", "TokenSource"]
@@ -1,12 +1,25 @@
1
1
  """HTTP utilities for CodeMie SDK."""
2
2
 
3
- from typing import TypeVar, Type, Optional, Any, Dict, List, get_origin, get_args
3
+ from typing import (
4
+ TypeVar,
5
+ Type,
6
+ Optional,
7
+ Any,
8
+ Dict,
9
+ List,
10
+ Callable,
11
+ Union,
12
+ get_origin,
13
+ get_args,
14
+ )
4
15
  import requests
5
16
  import logging
6
17
  from functools import wraps
7
18
 
8
19
  T = TypeVar("T")
9
20
 
21
+ TokenSource = Union[str, Callable[[], str]]
22
+
10
23
  logger = logging.getLogger(__name__)
11
24
 
12
25
 
@@ -33,12 +46,17 @@ def log_request(func):
33
46
  class ApiRequestHandler:
34
47
  """Handles HTTP requests with consistent error handling and response parsing."""
35
48
 
36
- def __init__(self, base_url: str, token: str, verify_ssl: bool = True):
49
+ def __init__(
50
+ self,
51
+ base_url: str,
52
+ token: Union[str, Callable[[], str]],
53
+ verify_ssl: bool = True,
54
+ ):
37
55
  """Initialize the API request handler.
38
56
 
39
57
  Args:
40
58
  base_url: Base URL for the API
41
- token: Authentication token
59
+ token: Authentication token string or callable that returns one
42
60
  verify_ssl: Whether to verify SSL certificates
43
61
  """
44
62
  self._base_url = base_url.rstrip("/")
@@ -72,11 +90,11 @@ class ApiRequestHandler:
72
90
  headers["Content-Type"] = "application/json"
73
91
 
74
92
  if include_auth:
75
- headers["Authorization"] = (
76
- f"Bearer {self._token}"
77
- if not self._is_localhost
78
- else "dev-codemie-user"
79
- )
93
+ if self._is_localhost:
94
+ headers["Authorization"] = "dev-codemie-user"
95
+ else:
96
+ token_value = self._token() if callable(self._token) else self._token
97
+ headers["Authorization"] = f"Bearer {token_value}"
80
98
  return headers
81
99
 
82
100
  def _parse_response(
@@ -1,5 +0,0 @@
1
- """Utility modules for CodeMie SDK."""
2
-
3
- from .http import ApiRequestHandler
4
-
5
- __all__ = ["ApiRequestHandler"]