amigo_sdk 0.62.0__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.
- amigo_sdk/__init__.py +4 -0
- amigo_sdk/_retry_utils.py +70 -0
- amigo_sdk/auth.py +48 -0
- amigo_sdk/config.py +48 -0
- amigo_sdk/errors.py +163 -0
- amigo_sdk/generated/model.py +16255 -0
- amigo_sdk/http_client.py +380 -0
- amigo_sdk/models.py +1 -0
- amigo_sdk/resources/conversation.py +361 -0
- amigo_sdk/resources/organization.py +34 -0
- amigo_sdk/resources/service.py +46 -0
- amigo_sdk/resources/user.py +97 -0
- amigo_sdk/sdk_client.py +187 -0
- amigo_sdk-0.62.0.dist-info/METADATA +260 -0
- amigo_sdk-0.62.0.dist-info/RECORD +18 -0
- amigo_sdk-0.62.0.dist-info/WHEEL +4 -0
- amigo_sdk-0.62.0.dist-info/entry_points.txt +3 -0
- amigo_sdk-0.62.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import threading
|
|
3
|
+
from collections.abc import AsyncGenerator, Iterator
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import AnyUrl, BaseModel
|
|
8
|
+
|
|
9
|
+
from amigo_sdk.generated.model import (
|
|
10
|
+
ConversationCreateConversationRequest,
|
|
11
|
+
ConversationCreateConversationResponse,
|
|
12
|
+
ConversationGenerateConversationStarterRequest,
|
|
13
|
+
ConversationGenerateConversationStarterResponse,
|
|
14
|
+
ConversationGetConversationMessagesResponse,
|
|
15
|
+
ConversationGetConversationsResponse,
|
|
16
|
+
ConversationGetInteractionInsightsResponse,
|
|
17
|
+
ConversationInteractWithConversationResponse,
|
|
18
|
+
ConversationRecommendResponsesForInteractionResponse,
|
|
19
|
+
CreateConversationParametersQuery,
|
|
20
|
+
Format,
|
|
21
|
+
GetConversationMessagesParametersQuery,
|
|
22
|
+
GetConversationsParametersQuery,
|
|
23
|
+
InteractWithConversationParametersQuery,
|
|
24
|
+
)
|
|
25
|
+
from amigo_sdk.http_client import AmigoAsyncHttpClient, AmigoHttpClient
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GetMessageSourceResponse(BaseModel):
|
|
29
|
+
"""
|
|
30
|
+
Response model for the `get_message_source` endpoint.
|
|
31
|
+
TODO: Remove once the OpenAPI spec contains the correct response model for this endpoint.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
url: AnyUrl
|
|
35
|
+
expires_at: datetime
|
|
36
|
+
content_type: Literal["audio/mpeg", "audio/wav"]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AsyncConversationResource:
|
|
40
|
+
"""Conversation resource for Amigo API operations."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, http_client: AmigoAsyncHttpClient, organization_id: str) -> None:
|
|
43
|
+
self._http = http_client
|
|
44
|
+
self._organization_id = organization_id
|
|
45
|
+
|
|
46
|
+
async def create_conversation(
|
|
47
|
+
self,
|
|
48
|
+
body: ConversationCreateConversationRequest,
|
|
49
|
+
params: CreateConversationParametersQuery,
|
|
50
|
+
abort_event: asyncio.Event | None = None,
|
|
51
|
+
) -> "AsyncGenerator[ConversationCreateConversationResponse, None]":
|
|
52
|
+
"""Create a new conversation and stream NDJSON events.
|
|
53
|
+
|
|
54
|
+
Returns an async generator yielding `ConversationCreateConversationResponse` events.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
async def _generator():
|
|
58
|
+
async for line in self._http.stream_lines(
|
|
59
|
+
"POST",
|
|
60
|
+
f"/v1/{self._organization_id}/conversation/",
|
|
61
|
+
params=params.model_dump(mode="json", exclude_none=True),
|
|
62
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
63
|
+
headers={"Accept": "application/x-ndjson"},
|
|
64
|
+
abort_event=abort_event,
|
|
65
|
+
):
|
|
66
|
+
# Each line is a JSON object representing a discriminated union event
|
|
67
|
+
yield ConversationCreateConversationResponse.model_validate_json(line)
|
|
68
|
+
|
|
69
|
+
return _generator()
|
|
70
|
+
|
|
71
|
+
async def interact_with_conversation(
|
|
72
|
+
self,
|
|
73
|
+
conversation_id: str,
|
|
74
|
+
params: InteractWithConversationParametersQuery,
|
|
75
|
+
abort_event: asyncio.Event | None = None,
|
|
76
|
+
*,
|
|
77
|
+
text_message: str | None = None,
|
|
78
|
+
audio_bytes: bytes | None = None,
|
|
79
|
+
audio_content_type: Literal["audio/mpeg", "audio/wav"] | None = None,
|
|
80
|
+
) -> "AsyncGenerator[ConversationInteractWithConversationResponse, None]":
|
|
81
|
+
"""Interact with a conversation and stream NDJSON events.
|
|
82
|
+
|
|
83
|
+
Returns an async generator yielding `ConversationInteractWithConversationResponse` events.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
async def _generator():
|
|
87
|
+
request_kwargs: dict[str, Any] = {
|
|
88
|
+
"params": params.model_dump(mode="json", exclude_none=True),
|
|
89
|
+
"abort_event": abort_event,
|
|
90
|
+
"headers": {"Accept": "application/x-ndjson"},
|
|
91
|
+
}
|
|
92
|
+
# Route based on requested format
|
|
93
|
+
req_format = getattr(params, "request_format", None)
|
|
94
|
+
if req_format == Format.text:
|
|
95
|
+
if text_message is None:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"text_message is required when request_format is 'text'"
|
|
98
|
+
)
|
|
99
|
+
text_bytes = text_message.encode("utf-8")
|
|
100
|
+
request_kwargs["files"] = {
|
|
101
|
+
"recorded_message": (
|
|
102
|
+
"message.txt",
|
|
103
|
+
text_bytes,
|
|
104
|
+
"text/plain; charset=utf-8",
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
elif req_format == Format.voice:
|
|
108
|
+
if audio_bytes is None or audio_content_type is None:
|
|
109
|
+
raise ValueError(
|
|
110
|
+
"audio_bytes and audio_content_type are required when request_format is 'voice'"
|
|
111
|
+
)
|
|
112
|
+
# Send raw bytes with appropriate content type
|
|
113
|
+
request_kwargs["content"] = audio_bytes
|
|
114
|
+
request_kwargs.setdefault("headers", {})
|
|
115
|
+
request_kwargs["headers"]["Content-Type"] = audio_content_type
|
|
116
|
+
else:
|
|
117
|
+
raise ValueError("Unsupported or missing request_format in params")
|
|
118
|
+
|
|
119
|
+
async for line in self._http.stream_lines(
|
|
120
|
+
"POST",
|
|
121
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/interact",
|
|
122
|
+
**request_kwargs,
|
|
123
|
+
):
|
|
124
|
+
# Each line is a JSON object representing a discriminated union event
|
|
125
|
+
yield ConversationInteractWithConversationResponse.model_validate_json(
|
|
126
|
+
line
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
return _generator()
|
|
130
|
+
|
|
131
|
+
async def finish_conversation(self, conversation_id: str) -> None:
|
|
132
|
+
"""Finish a conversation."""
|
|
133
|
+
await self._http.request(
|
|
134
|
+
"POST",
|
|
135
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/finish/",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
async def get_conversations(
|
|
139
|
+
self, params: GetConversationsParametersQuery
|
|
140
|
+
) -> ConversationGetConversationsResponse:
|
|
141
|
+
"""Get conversations."""
|
|
142
|
+
response = await self._http.request(
|
|
143
|
+
"GET",
|
|
144
|
+
f"/v1/{self._organization_id}/conversation/",
|
|
145
|
+
params=params.model_dump(mode="json", exclude_none=True),
|
|
146
|
+
)
|
|
147
|
+
return ConversationGetConversationsResponse.model_validate_json(response.text)
|
|
148
|
+
|
|
149
|
+
async def get_conversation_messages(
|
|
150
|
+
self, conversation_id: str, params: GetConversationMessagesParametersQuery
|
|
151
|
+
) -> ConversationGetConversationMessagesResponse:
|
|
152
|
+
"""Get conversation messages."""
|
|
153
|
+
response = await self._http.request(
|
|
154
|
+
"GET",
|
|
155
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/messages/",
|
|
156
|
+
params=params.model_dump(
|
|
157
|
+
mode="json", exclude_none=True, exclude_defaults=True
|
|
158
|
+
),
|
|
159
|
+
)
|
|
160
|
+
return ConversationGetConversationMessagesResponse.model_validate_json(
|
|
161
|
+
response.text
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
async def recommend_responses_for_interaction(
|
|
165
|
+
self, conversation_id: str, interaction_id: str
|
|
166
|
+
) -> ConversationRecommendResponsesForInteractionResponse:
|
|
167
|
+
"""Recommend responses for an interaction."""
|
|
168
|
+
response = await self._http.request(
|
|
169
|
+
"GET",
|
|
170
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/interaction/{interaction_id}/recommend_responses",
|
|
171
|
+
)
|
|
172
|
+
return ConversationRecommendResponsesForInteractionResponse.model_validate_json(
|
|
173
|
+
response.text
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
async def get_interaction_insights(
|
|
177
|
+
self, conversation_id: str, interaction_id: str
|
|
178
|
+
) -> ConversationGetInteractionInsightsResponse:
|
|
179
|
+
"""Get insights for an interaction."""
|
|
180
|
+
response = await self._http.request(
|
|
181
|
+
"GET",
|
|
182
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/interaction/{interaction_id}/insights",
|
|
183
|
+
)
|
|
184
|
+
return ConversationGetInteractionInsightsResponse.model_validate_json(
|
|
185
|
+
response.text
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
async def get_message_source(
|
|
189
|
+
self, conversation_id: str, message_id: str
|
|
190
|
+
) -> GetMessageSourceResponse:
|
|
191
|
+
"""Get the source of a message."""
|
|
192
|
+
response = await self._http.request(
|
|
193
|
+
"GET",
|
|
194
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/messages/{message_id}/source",
|
|
195
|
+
)
|
|
196
|
+
return GetMessageSourceResponse.model_validate_json(response.text)
|
|
197
|
+
|
|
198
|
+
async def generate_conversation_starters(
|
|
199
|
+
self, body: ConversationGenerateConversationStarterRequest
|
|
200
|
+
) -> ConversationGenerateConversationStarterResponse:
|
|
201
|
+
"""Generate conversation starters."""
|
|
202
|
+
response = await self._http.request(
|
|
203
|
+
"POST",
|
|
204
|
+
f"/v1/{self._organization_id}/conversation/conversation_starter",
|
|
205
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
206
|
+
)
|
|
207
|
+
return ConversationGenerateConversationStarterResponse.model_validate_json(
|
|
208
|
+
response.text
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class ConversationResource:
|
|
213
|
+
"""Conversation resource for synchronous operations."""
|
|
214
|
+
|
|
215
|
+
def __init__(self, http_client: AmigoHttpClient, organization_id: str) -> None:
|
|
216
|
+
self._http = http_client
|
|
217
|
+
self._organization_id = organization_id
|
|
218
|
+
|
|
219
|
+
def create_conversation(
|
|
220
|
+
self,
|
|
221
|
+
body: ConversationCreateConversationRequest,
|
|
222
|
+
params: CreateConversationParametersQuery,
|
|
223
|
+
abort_event: threading.Event | None = None,
|
|
224
|
+
) -> Iterator[ConversationCreateConversationResponse]:
|
|
225
|
+
def _iter():
|
|
226
|
+
for line in self._http.stream_lines(
|
|
227
|
+
"POST",
|
|
228
|
+
f"/v1/{self._organization_id}/conversation/",
|
|
229
|
+
params=params.model_dump(mode="json", exclude_none=True),
|
|
230
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
231
|
+
headers={"Accept": "application/x-ndjson"},
|
|
232
|
+
abort_event=abort_event,
|
|
233
|
+
):
|
|
234
|
+
yield ConversationCreateConversationResponse.model_validate_json(line)
|
|
235
|
+
|
|
236
|
+
return _iter()
|
|
237
|
+
|
|
238
|
+
def interact_with_conversation(
|
|
239
|
+
self,
|
|
240
|
+
conversation_id: str,
|
|
241
|
+
params: InteractWithConversationParametersQuery,
|
|
242
|
+
abort_event: threading.Event | None = None,
|
|
243
|
+
*,
|
|
244
|
+
text_message: str | None = None,
|
|
245
|
+
audio_bytes: bytes | None = None,
|
|
246
|
+
audio_content_type: Literal["audio/mpeg", "audio/wav"] | None = None,
|
|
247
|
+
) -> Iterator[ConversationInteractWithConversationResponse]:
|
|
248
|
+
def _iter():
|
|
249
|
+
request_kwargs: dict[str, Any] = {
|
|
250
|
+
"params": params.model_dump(mode="json", exclude_none=True),
|
|
251
|
+
"headers": {"Accept": "application/x-ndjson"},
|
|
252
|
+
"abort_event": abort_event,
|
|
253
|
+
}
|
|
254
|
+
req_format = getattr(params, "request_format", None)
|
|
255
|
+
if req_format == Format.text:
|
|
256
|
+
if text_message is None:
|
|
257
|
+
raise ValueError(
|
|
258
|
+
"text_message is required when request_format is 'text'"
|
|
259
|
+
)
|
|
260
|
+
text_bytes = text_message.encode("utf-8")
|
|
261
|
+
request_kwargs["files"] = {
|
|
262
|
+
"recorded_message": (
|
|
263
|
+
"message.txt",
|
|
264
|
+
text_bytes,
|
|
265
|
+
"text/plain; charset=utf-8",
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
elif req_format == Format.voice:
|
|
269
|
+
if audio_bytes is None or audio_content_type is None:
|
|
270
|
+
raise ValueError(
|
|
271
|
+
"audio_bytes and audio_content_type are required when request_format is 'voice'"
|
|
272
|
+
)
|
|
273
|
+
request_kwargs["content"] = audio_bytes
|
|
274
|
+
request_kwargs.setdefault("headers", {})
|
|
275
|
+
request_kwargs["headers"]["Content-Type"] = audio_content_type
|
|
276
|
+
else:
|
|
277
|
+
raise ValueError("Unsupported or missing request_format in params")
|
|
278
|
+
|
|
279
|
+
for line in self._http.stream_lines(
|
|
280
|
+
"POST",
|
|
281
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/interact",
|
|
282
|
+
**request_kwargs,
|
|
283
|
+
):
|
|
284
|
+
yield ConversationInteractWithConversationResponse.model_validate_json(
|
|
285
|
+
line
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
return _iter()
|
|
289
|
+
|
|
290
|
+
def finish_conversation(self, conversation_id: str) -> None:
|
|
291
|
+
self._http.request(
|
|
292
|
+
"POST",
|
|
293
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/finish/",
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
def get_conversations(
|
|
297
|
+
self, params: GetConversationsParametersQuery
|
|
298
|
+
) -> ConversationGetConversationsResponse:
|
|
299
|
+
response = self._http.request(
|
|
300
|
+
"GET",
|
|
301
|
+
f"/v1/{self._organization_id}/conversation/",
|
|
302
|
+
params=params.model_dump(mode="json", exclude_none=True),
|
|
303
|
+
)
|
|
304
|
+
return ConversationGetConversationsResponse.model_validate_json(response.text)
|
|
305
|
+
|
|
306
|
+
def get_conversation_messages(
|
|
307
|
+
self, conversation_id: str, params: GetConversationMessagesParametersQuery
|
|
308
|
+
) -> ConversationGetConversationMessagesResponse:
|
|
309
|
+
response = self._http.request(
|
|
310
|
+
"GET",
|
|
311
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/messages/",
|
|
312
|
+
params=params.model_dump(
|
|
313
|
+
mode="json", exclude_none=True, exclude_defaults=True
|
|
314
|
+
),
|
|
315
|
+
)
|
|
316
|
+
return ConversationGetConversationMessagesResponse.model_validate_json(
|
|
317
|
+
response.text
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
def recommend_responses_for_interaction(
|
|
321
|
+
self, conversation_id: str, interaction_id: str
|
|
322
|
+
) -> ConversationRecommendResponsesForInteractionResponse:
|
|
323
|
+
response = self._http.request(
|
|
324
|
+
"GET",
|
|
325
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/interaction/{interaction_id}/recommend_responses",
|
|
326
|
+
)
|
|
327
|
+
return ConversationRecommendResponsesForInteractionResponse.model_validate_json(
|
|
328
|
+
response.text
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
def get_interaction_insights(
|
|
332
|
+
self, conversation_id: str, interaction_id: str
|
|
333
|
+
) -> ConversationGetInteractionInsightsResponse:
|
|
334
|
+
response = self._http.request(
|
|
335
|
+
"GET",
|
|
336
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/interaction/{interaction_id}/insights",
|
|
337
|
+
)
|
|
338
|
+
return ConversationGetInteractionInsightsResponse.model_validate_json(
|
|
339
|
+
response.text
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
def get_message_source(
|
|
343
|
+
self, conversation_id: str, message_id: str
|
|
344
|
+
) -> GetMessageSourceResponse:
|
|
345
|
+
response = self._http.request(
|
|
346
|
+
"GET",
|
|
347
|
+
f"/v1/{self._organization_id}/conversation/{conversation_id}/messages/{message_id}/source",
|
|
348
|
+
)
|
|
349
|
+
return GetMessageSourceResponse.model_validate_json(response.text)
|
|
350
|
+
|
|
351
|
+
def generate_conversation_starters(
|
|
352
|
+
self, body: ConversationGenerateConversationStarterRequest
|
|
353
|
+
) -> ConversationGenerateConversationStarterResponse:
|
|
354
|
+
response = self._http.request(
|
|
355
|
+
"POST",
|
|
356
|
+
f"/v1/{self._organization_id}/conversation/conversation_starter",
|
|
357
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
358
|
+
)
|
|
359
|
+
return ConversationGenerateConversationStarterResponse.model_validate_json(
|
|
360
|
+
response.text
|
|
361
|
+
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from amigo_sdk.generated.model import (
|
|
2
|
+
OrganizationGetOrganizationResponse,
|
|
3
|
+
)
|
|
4
|
+
from amigo_sdk.http_client import AmigoAsyncHttpClient, AmigoHttpClient
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AsyncOrganizationResource:
|
|
8
|
+
"""Organization resource for Amigo API operations."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, http_client: AmigoAsyncHttpClient, organization_id: str) -> None:
|
|
11
|
+
self._http = http_client
|
|
12
|
+
self._organization_id = organization_id
|
|
13
|
+
|
|
14
|
+
async def get(self) -> OrganizationGetOrganizationResponse:
|
|
15
|
+
"""
|
|
16
|
+
Get the details of an organization.
|
|
17
|
+
"""
|
|
18
|
+
response = await self._http.request(
|
|
19
|
+
"GET", f"/v1/{self._organization_id}/organization/"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
return OrganizationGetOrganizationResponse.model_validate_json(response.text)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class OrganizationResource:
|
|
26
|
+
def __init__(self, http_client: AmigoHttpClient, organization_id: str) -> None:
|
|
27
|
+
self._http = http_client
|
|
28
|
+
self._organization_id = organization_id
|
|
29
|
+
|
|
30
|
+
def get(self) -> OrganizationGetOrganizationResponse:
|
|
31
|
+
response = self._http.request(
|
|
32
|
+
"GET", f"/v1/{self._organization_id}/organization/"
|
|
33
|
+
)
|
|
34
|
+
return OrganizationGetOrganizationResponse.model_validate_json(response.text)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from amigo_sdk.generated.model import (
|
|
4
|
+
GetServicesParametersQuery,
|
|
5
|
+
ServiceGetServicesResponse,
|
|
6
|
+
)
|
|
7
|
+
from amigo_sdk.http_client import AmigoAsyncHttpClient, AmigoHttpClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AsyncServiceResource:
|
|
11
|
+
"""Service resource for Amigo API operations."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, http_client: AmigoAsyncHttpClient, organization_id: str) -> None:
|
|
14
|
+
self._http = http_client
|
|
15
|
+
self._organization_id = organization_id
|
|
16
|
+
|
|
17
|
+
async def get_services(
|
|
18
|
+
self, params: Optional[GetServicesParametersQuery] = None
|
|
19
|
+
) -> ServiceGetServicesResponse:
|
|
20
|
+
"""Get all services."""
|
|
21
|
+
response = await self._http.request(
|
|
22
|
+
"GET",
|
|
23
|
+
f"/v1/{self._organization_id}/service/",
|
|
24
|
+
params=params.model_dump(mode="json", exclude_none=True)
|
|
25
|
+
if params
|
|
26
|
+
else None,
|
|
27
|
+
)
|
|
28
|
+
return ServiceGetServicesResponse.model_validate_json(response.text)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ServiceResource:
|
|
32
|
+
def __init__(self, http_client: AmigoHttpClient, organization_id: str) -> None:
|
|
33
|
+
self._http = http_client
|
|
34
|
+
self._organization_id = organization_id
|
|
35
|
+
|
|
36
|
+
def get_services(
|
|
37
|
+
self, params: Optional[GetServicesParametersQuery] = None
|
|
38
|
+
) -> ServiceGetServicesResponse:
|
|
39
|
+
response = self._http.request(
|
|
40
|
+
"GET",
|
|
41
|
+
f"/v1/{self._organization_id}/service/",
|
|
42
|
+
params=params.model_dump(mode="json", exclude_none=True)
|
|
43
|
+
if params
|
|
44
|
+
else None,
|
|
45
|
+
)
|
|
46
|
+
return ServiceGetServicesResponse.model_validate_json(response.text)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from amigo_sdk.generated.model import (
|
|
4
|
+
GetUsersParametersQuery,
|
|
5
|
+
UserCreateInvitedUserRequest,
|
|
6
|
+
UserCreateInvitedUserResponse,
|
|
7
|
+
UserGetUsersResponse,
|
|
8
|
+
UserUpdateUserInfoRequest,
|
|
9
|
+
)
|
|
10
|
+
from amigo_sdk.http_client import AmigoAsyncHttpClient, AmigoHttpClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AsyncUserResource:
|
|
14
|
+
"""User resource for Amigo API operations."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, http_client: AmigoAsyncHttpClient, organization_id: str) -> None:
|
|
17
|
+
self._http = http_client
|
|
18
|
+
self._organization_id = organization_id
|
|
19
|
+
|
|
20
|
+
async def get_users(
|
|
21
|
+
self, params: Optional[GetUsersParametersQuery] = None
|
|
22
|
+
) -> UserGetUsersResponse:
|
|
23
|
+
"""Get a list of users in the organization."""
|
|
24
|
+
response = await self._http.request(
|
|
25
|
+
"GET",
|
|
26
|
+
f"/v1/{self._organization_id}/user/",
|
|
27
|
+
params=params.model_dump(mode="json", exclude_none=True)
|
|
28
|
+
if params
|
|
29
|
+
else None,
|
|
30
|
+
)
|
|
31
|
+
return UserGetUsersResponse.model_validate_json(response.text)
|
|
32
|
+
|
|
33
|
+
async def create_user(
|
|
34
|
+
self, body: UserCreateInvitedUserRequest
|
|
35
|
+
) -> UserCreateInvitedUserResponse:
|
|
36
|
+
"""Create (invite) a new user to the organization."""
|
|
37
|
+
response = await self._http.request(
|
|
38
|
+
"POST",
|
|
39
|
+
f"/v1/{self._organization_id}/user/",
|
|
40
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
41
|
+
)
|
|
42
|
+
return UserCreateInvitedUserResponse.model_validate_json(response.text)
|
|
43
|
+
|
|
44
|
+
async def delete_user(self, user_id: str) -> None:
|
|
45
|
+
"""Delete a user by ID. Returns None on success (e.g., 204)."""
|
|
46
|
+
await self._http.request(
|
|
47
|
+
"DELETE",
|
|
48
|
+
f"/v1/{self._organization_id}/user/{user_id}",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
async def update_user(self, user_id: str, body: UserUpdateUserInfoRequest) -> None:
|
|
52
|
+
"""Update user information. Returns None on success (e.g., 204)."""
|
|
53
|
+
await self._http.request(
|
|
54
|
+
"POST",
|
|
55
|
+
f"/v1/{self._organization_id}/user/{user_id}/user",
|
|
56
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class UserResource:
|
|
61
|
+
"""User resource (synchronous)."""
|
|
62
|
+
|
|
63
|
+
def __init__(self, http_client: AmigoHttpClient, organization_id: str) -> None:
|
|
64
|
+
self._http = http_client
|
|
65
|
+
self._organization_id = organization_id
|
|
66
|
+
|
|
67
|
+
def get_users(
|
|
68
|
+
self, params: Optional[GetUsersParametersQuery] = None
|
|
69
|
+
) -> UserGetUsersResponse:
|
|
70
|
+
response = self._http.request(
|
|
71
|
+
"GET",
|
|
72
|
+
f"/v1/{self._organization_id}/user/",
|
|
73
|
+
params=params.model_dump(mode="json", exclude_none=True)
|
|
74
|
+
if params
|
|
75
|
+
else None,
|
|
76
|
+
)
|
|
77
|
+
return UserGetUsersResponse.model_validate_json(response.text)
|
|
78
|
+
|
|
79
|
+
def create_user(
|
|
80
|
+
self, body: UserCreateInvitedUserRequest
|
|
81
|
+
) -> UserCreateInvitedUserResponse:
|
|
82
|
+
response = self._http.request(
|
|
83
|
+
"POST",
|
|
84
|
+
f"/v1/{self._organization_id}/user/",
|
|
85
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
86
|
+
)
|
|
87
|
+
return UserCreateInvitedUserResponse.model_validate_json(response.text)
|
|
88
|
+
|
|
89
|
+
def delete_user(self, user_id: str) -> None:
|
|
90
|
+
self._http.request("DELETE", f"/v1/{self._organization_id}/user/{user_id}")
|
|
91
|
+
|
|
92
|
+
def update_user(self, user_id: str, body: UserUpdateUserInfoRequest) -> None:
|
|
93
|
+
self._http.request(
|
|
94
|
+
"POST",
|
|
95
|
+
f"/v1/{self._organization_id}/user/{user_id}/user",
|
|
96
|
+
json=body.model_dump(mode="json", exclude_none=True),
|
|
97
|
+
)
|