assistant-runtime-sdk 1.0.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.
- assistant_runtime_sdk/__init__.py +235 -0
- assistant_runtime_sdk/async_client.py +1989 -0
- assistant_runtime_sdk/auth.py +161 -0
- assistant_runtime_sdk/base.py +2277 -0
- assistant_runtime_sdk/client.py +3039 -0
- assistant_runtime_sdk/exceptions.py +146 -0
- assistant_runtime_sdk/skills.py +328 -0
- assistant_runtime_sdk/streaming.py +223 -0
- assistant_runtime_sdk/types.py +546 -0
- assistant_runtime_sdk-1.0.0.dist-info/METADATA +259 -0
- assistant_runtime_sdk-1.0.0.dist-info/RECORD +13 -0
- assistant_runtime_sdk-1.0.0.dist-info/WHEEL +4 -0
- assistant_runtime_sdk-1.0.0.dist-info/licenses/LICENSE +17 -0
|
@@ -0,0 +1,1989 @@
|
|
|
1
|
+
# Assistant Runtime SDK - Asynchronous Client
|
|
2
|
+
# Copyright (C) 2025 Paul Clinton
|
|
3
|
+
# AGPL-3.0 License
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Asynchronous Assistant Runtime client using aiohttp.
|
|
7
|
+
|
|
8
|
+
Requires the 'async' extra: pip install assistant_runtime_sdk[async]
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from typing import AsyncGenerator, List, Optional, Dict, Any
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
import aiohttp
|
|
16
|
+
except ImportError:
|
|
17
|
+
aiohttp = None # type: ignore
|
|
18
|
+
|
|
19
|
+
from .base import BaseAssistantRuntimeClient
|
|
20
|
+
from .exceptions import (
|
|
21
|
+
ARAPIError,
|
|
22
|
+
ARAuthenticationError,
|
|
23
|
+
ARTimeoutError,
|
|
24
|
+
ARConnectionError,
|
|
25
|
+
ARConfigurationError,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AsyncAssistantRuntimeClient(BaseAssistantRuntimeClient):
|
|
30
|
+
"""
|
|
31
|
+
Asynchronous Assistant Runtime client using aiohttp.
|
|
32
|
+
|
|
33
|
+
Use as an async context manager for proper resource management.
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
>>> async with AsyncAssistantRuntimeClient("tenant-id", "secret") as client:
|
|
37
|
+
... models = await client.list_available_models()
|
|
38
|
+
... async for event in client.stream_chat("session-1", "Hello", "user@example.com"):
|
|
39
|
+
... print(event)
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
tenant_id: str,
|
|
45
|
+
tenant_secret: str,
|
|
46
|
+
ar_url: str = BaseAssistantRuntimeClient.DEFAULT_AR_URL,
|
|
47
|
+
logger=None,
|
|
48
|
+
timeout: float = BaseAssistantRuntimeClient.DEFAULT_TIMEOUT,
|
|
49
|
+
session: Optional["aiohttp.ClientSession"] = None,
|
|
50
|
+
billing_api_base: Optional[str] = None,
|
|
51
|
+
memory_api_base: Optional[str] = None,
|
|
52
|
+
workflows_api_base: Optional[str] = None,
|
|
53
|
+
marketplace_api_base: Optional[str] = None,
|
|
54
|
+
voice_api_base: Optional[str] = None,
|
|
55
|
+
site_url: Optional[str] = None,
|
|
56
|
+
):
|
|
57
|
+
"""
|
|
58
|
+
Initialize async Assistant Runtime client.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
tenant_id: Unique tenant identifier from Assistant Runtime
|
|
62
|
+
tenant_secret: HMAC secret for request signing
|
|
63
|
+
ar_url: Base URL of Assistant Runtime server
|
|
64
|
+
logger: Optional logger instance
|
|
65
|
+
timeout: Default request timeout in seconds
|
|
66
|
+
session: Optional aiohttp.ClientSession to reuse
|
|
67
|
+
billing_api_base: Override URL for billing API endpoints
|
|
68
|
+
memory_api_base: Override URL for memory/onboarding/document API endpoints
|
|
69
|
+
workflows_api_base: Override URL for workflow API endpoints
|
|
70
|
+
marketplace_api_base: Override URL for marketplace API endpoints
|
|
71
|
+
voice_api_base: Override URL for voice/transcription API endpoints
|
|
72
|
+
site_url: This installation's canonical URL (e.g. ``"https://mysite.example.com"``).
|
|
73
|
+
Automatically included in signed payloads for origin binding (Phase 2).
|
|
74
|
+
"""
|
|
75
|
+
if aiohttp is None:
|
|
76
|
+
raise ImportError(
|
|
77
|
+
"aiohttp is required for AsyncAssistantRuntimeClient. "
|
|
78
|
+
"Install it with: pip install assistant_runtime_sdk[async]"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
super().__init__(
|
|
82
|
+
tenant_id, tenant_secret, ar_url, logger, timeout,
|
|
83
|
+
billing_api_base, memory_api_base, workflows_api_base,
|
|
84
|
+
marketplace_api_base, voice_api_base, site_url,
|
|
85
|
+
)
|
|
86
|
+
self._session = session
|
|
87
|
+
self._owns_session = session is None
|
|
88
|
+
|
|
89
|
+
async def __aenter__(self) -> "AsyncAssistantRuntimeClient":
|
|
90
|
+
"""Enter async context - create session if needed."""
|
|
91
|
+
if self._owns_session:
|
|
92
|
+
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
|
93
|
+
self._session = aiohttp.ClientSession(timeout=timeout)
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
97
|
+
"""Exit async context - close session if we own it."""
|
|
98
|
+
if self._owns_session and self._session:
|
|
99
|
+
await self._session.close()
|
|
100
|
+
self._session = None
|
|
101
|
+
|
|
102
|
+
def _ensure_session(self) -> "aiohttp.ClientSession":
|
|
103
|
+
"""Ensure we have an active session."""
|
|
104
|
+
if self._session is None:
|
|
105
|
+
raise ARConfigurationError(
|
|
106
|
+
"No active session. Use AsyncAssistantRuntimeClient as a context manager: "
|
|
107
|
+
"async with AsyncAssistantRuntimeClient(...) as client:"
|
|
108
|
+
)
|
|
109
|
+
return self._session
|
|
110
|
+
|
|
111
|
+
# =========================================================================
|
|
112
|
+
# Internal Request Methods
|
|
113
|
+
# =========================================================================
|
|
114
|
+
|
|
115
|
+
async def _handle_error_response(
|
|
116
|
+
self, response: "aiohttp.ClientResponse", endpoint: str, method: str,
|
|
117
|
+
) -> None:
|
|
118
|
+
"""Check response status and raise appropriate exceptions.
|
|
119
|
+
|
|
120
|
+
Must be called BEFORE raise_for_status() so we can read the body
|
|
121
|
+
and raise specific exception types (e.g. ARAuthenticationError for 401).
|
|
122
|
+
"""
|
|
123
|
+
if response.status < 400:
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
# Read error body for better messages. The full payload is
|
|
127
|
+
# forwarded to ARAPIError.response_data so callers can read
|
|
128
|
+
# any extra keys AR set (e.g. tenant_owner_user_id).
|
|
129
|
+
msg = None
|
|
130
|
+
data: Optional[Dict[str, Any]] = None
|
|
131
|
+
try:
|
|
132
|
+
data = await response.json()
|
|
133
|
+
msg = self._extract_error_from_data(data)
|
|
134
|
+
except Exception:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
if response.status == 401:
|
|
138
|
+
raise ARAuthenticationError(msg or "Authentication failed")
|
|
139
|
+
|
|
140
|
+
raise ARAPIError(
|
|
141
|
+
msg or f"{method} {endpoint} failed with status {response.status}",
|
|
142
|
+
status_code=response.status,
|
|
143
|
+
response_data=data,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
async def _request_get(
|
|
147
|
+
self,
|
|
148
|
+
endpoint: str,
|
|
149
|
+
params: Dict[str, Any],
|
|
150
|
+
timeout: Optional[float] = None,
|
|
151
|
+
api_base: Optional[str] = None,
|
|
152
|
+
) -> Optional[Dict[str, Any]]:
|
|
153
|
+
"""Make authenticated async GET request."""
|
|
154
|
+
session = self._ensure_session()
|
|
155
|
+
url = f"{api_base}.{endpoint}" if api_base else self._build_endpoint_url(endpoint)
|
|
156
|
+
params = self._with_site_url(params)
|
|
157
|
+
headers = self._get_headers(params, for_query_string=True)
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
timeout_obj = aiohttp.ClientTimeout(total=timeout or self.timeout)
|
|
161
|
+
async with session.get(url, params=params, headers=headers, timeout=timeout_obj) as response:
|
|
162
|
+
await self._handle_error_response(response, endpoint, "GET")
|
|
163
|
+
data = await response.json()
|
|
164
|
+
return data.get("message", data)
|
|
165
|
+
except (ARAuthenticationError, ARAPIError):
|
|
166
|
+
raise
|
|
167
|
+
except aiohttp.ServerTimeoutError as e:
|
|
168
|
+
self._log_error(f"GET {endpoint} timeout: {e}")
|
|
169
|
+
raise ARTimeoutError(f"Request to {endpoint} timed out") from e
|
|
170
|
+
except aiohttp.ClientConnectorError as e:
|
|
171
|
+
self._log_error(f"GET {endpoint} connection error: {e}")
|
|
172
|
+
raise ARConnectionError(f"Failed to connect to {endpoint}") from e
|
|
173
|
+
except aiohttp.ClientError as e:
|
|
174
|
+
self._log_error(f"GET {endpoint} error: {e}")
|
|
175
|
+
raise ARAPIError(str(e)) from e
|
|
176
|
+
|
|
177
|
+
async def _request_get_raw(
|
|
178
|
+
self,
|
|
179
|
+
endpoint: str,
|
|
180
|
+
params: Dict[str, Any],
|
|
181
|
+
timeout: Optional[float] = None,
|
|
182
|
+
api_base: Optional[str] = None,
|
|
183
|
+
) -> tuple:
|
|
184
|
+
"""Make authenticated async GET request expecting raw binary response.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
(content_bytes, content_type, filename) tuple
|
|
188
|
+
"""
|
|
189
|
+
session = self._ensure_session()
|
|
190
|
+
url = f"{api_base}.{endpoint}" if api_base else self._build_endpoint_url(endpoint)
|
|
191
|
+
params = self._with_site_url(params)
|
|
192
|
+
headers = self._get_headers(params, for_query_string=True)
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
timeout_obj = aiohttp.ClientTimeout(total=timeout or self.timeout)
|
|
196
|
+
async with session.get(url, params=params, headers=headers, timeout=timeout_obj) as response:
|
|
197
|
+
await self._handle_error_response(response, endpoint, "GET raw")
|
|
198
|
+
content = await response.read()
|
|
199
|
+
|
|
200
|
+
content_type = response.headers.get("Content-Type", "application/octet-stream")
|
|
201
|
+
filename = ""
|
|
202
|
+
cd = response.headers.get("Content-Disposition", "")
|
|
203
|
+
if "filename=" in cd:
|
|
204
|
+
parts = cd.split("filename=")
|
|
205
|
+
if len(parts) > 1:
|
|
206
|
+
filename = parts[1].strip().strip('"')
|
|
207
|
+
|
|
208
|
+
return content, content_type, filename
|
|
209
|
+
except (ARAuthenticationError, ARAPIError):
|
|
210
|
+
raise
|
|
211
|
+
except aiohttp.ServerTimeoutError as e:
|
|
212
|
+
self._log_error(f"GET raw {endpoint} timeout: {e}")
|
|
213
|
+
raise ARTimeoutError(f"Request to {endpoint} timed out") from e
|
|
214
|
+
except aiohttp.ClientConnectorError as e:
|
|
215
|
+
self._log_error(f"GET raw {endpoint} connection error: {e}")
|
|
216
|
+
raise ARConnectionError(f"Failed to connect to {endpoint}") from e
|
|
217
|
+
except aiohttp.ClientError as e:
|
|
218
|
+
self._log_error(f"GET raw {endpoint} error: {e}")
|
|
219
|
+
raise ARAPIError(str(e)) from e
|
|
220
|
+
|
|
221
|
+
async def _request_post_json(
|
|
222
|
+
self,
|
|
223
|
+
endpoint: str,
|
|
224
|
+
payload: Dict[str, Any],
|
|
225
|
+
timeout: Optional[float] = None,
|
|
226
|
+
api_base: Optional[str] = None,
|
|
227
|
+
) -> Optional[Dict[str, Any]]:
|
|
228
|
+
"""Make authenticated async POST request with JSON body."""
|
|
229
|
+
session = self._ensure_session()
|
|
230
|
+
url = f"{api_base}.{endpoint}" if api_base else self._build_endpoint_url(endpoint)
|
|
231
|
+
payload = self._with_site_url(payload)
|
|
232
|
+
headers = {
|
|
233
|
+
**self._get_headers(payload, for_query_string=False),
|
|
234
|
+
"Content-Type": "application/json",
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
timeout_obj = aiohttp.ClientTimeout(total=timeout or self.timeout)
|
|
239
|
+
async with session.post(url, json=payload, headers=headers, timeout=timeout_obj) as response:
|
|
240
|
+
await self._handle_error_response(response, endpoint, "POST")
|
|
241
|
+
data = await response.json()
|
|
242
|
+
return data.get("message", data)
|
|
243
|
+
except (ARAuthenticationError, ARAPIError):
|
|
244
|
+
raise
|
|
245
|
+
except aiohttp.ServerTimeoutError as e:
|
|
246
|
+
self._log_error(f"POST {endpoint} timeout: {e}")
|
|
247
|
+
raise ARTimeoutError(f"Request to {endpoint} timed out") from e
|
|
248
|
+
except aiohttp.ClientConnectorError as e:
|
|
249
|
+
self._log_error(f"POST {endpoint} connection error: {e}")
|
|
250
|
+
raise ARConnectionError(f"Failed to connect to {endpoint}") from e
|
|
251
|
+
except aiohttp.ClientError as e:
|
|
252
|
+
self._log_error(f"POST {endpoint} error: {e}")
|
|
253
|
+
raise ARAPIError(str(e)) from e
|
|
254
|
+
|
|
255
|
+
async def _request_post_form(
|
|
256
|
+
self,
|
|
257
|
+
endpoint: str,
|
|
258
|
+
params: Dict[str, Any],
|
|
259
|
+
timeout: Optional[float] = None,
|
|
260
|
+
api_base: Optional[str] = None,
|
|
261
|
+
) -> Optional[Dict[str, Any]]:
|
|
262
|
+
"""Make authenticated async POST request with form-urlencoded body."""
|
|
263
|
+
session = self._ensure_session()
|
|
264
|
+
url = f"{api_base}.{endpoint}" if api_base else self._build_endpoint_url(endpoint)
|
|
265
|
+
params = self._with_site_url(params)
|
|
266
|
+
headers = {
|
|
267
|
+
**self._get_headers(params, for_query_string=True),
|
|
268
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
timeout_obj = aiohttp.ClientTimeout(total=timeout or self.timeout)
|
|
273
|
+
async with session.post(url, data=params, headers=headers, timeout=timeout_obj) as response:
|
|
274
|
+
await self._handle_error_response(response, endpoint, "POST form")
|
|
275
|
+
data = await response.json()
|
|
276
|
+
return data.get("message", data)
|
|
277
|
+
except (ARAuthenticationError, ARAPIError):
|
|
278
|
+
raise
|
|
279
|
+
except aiohttp.ServerTimeoutError as e:
|
|
280
|
+
self._log_error(f"POST form {endpoint} timeout: {e}")
|
|
281
|
+
raise ARTimeoutError(f"Request to {endpoint} timed out") from e
|
|
282
|
+
except aiohttp.ClientConnectorError as e:
|
|
283
|
+
self._log_error(f"POST form {endpoint} connection error: {e}")
|
|
284
|
+
raise ARConnectionError(f"Failed to connect to {endpoint}") from e
|
|
285
|
+
except aiohttp.ClientError as e:
|
|
286
|
+
self._log_error(f"POST form {endpoint} error: {e}")
|
|
287
|
+
raise ARAPIError(str(e)) from e
|
|
288
|
+
|
|
289
|
+
async def _request_post_multipart(
|
|
290
|
+
self,
|
|
291
|
+
endpoint: str,
|
|
292
|
+
params: Dict[str, Any],
|
|
293
|
+
file_field: str,
|
|
294
|
+
file_name: str,
|
|
295
|
+
file_data: bytes,
|
|
296
|
+
content_type: str = "application/octet-stream",
|
|
297
|
+
timeout: Optional[float] = None,
|
|
298
|
+
api_base: Optional[str] = None,
|
|
299
|
+
) -> Optional[Dict[str, Any]]:
|
|
300
|
+
"""Make authenticated async POST request with multipart form data including a file."""
|
|
301
|
+
session = self._ensure_session()
|
|
302
|
+
url = f"{api_base}.{endpoint}" if api_base else self._build_endpoint_url(endpoint)
|
|
303
|
+
# Sign only non-file form fields — Frappe's form_dict excludes file parts
|
|
304
|
+
params = self._with_site_url(params)
|
|
305
|
+
headers = self._get_headers(params, for_query_string=True)
|
|
306
|
+
# Do NOT set Content-Type — aiohttp sets multipart boundary automatically
|
|
307
|
+
|
|
308
|
+
form_data = aiohttp.FormData()
|
|
309
|
+
for key, value in params.items():
|
|
310
|
+
form_data.add_field(key, str(value))
|
|
311
|
+
form_data.add_field(
|
|
312
|
+
file_field, file_data,
|
|
313
|
+
filename=file_name,
|
|
314
|
+
content_type=content_type,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
try:
|
|
318
|
+
timeout_obj = aiohttp.ClientTimeout(total=timeout or self.timeout)
|
|
319
|
+
async with session.post(url, data=form_data, headers=headers, timeout=timeout_obj) as response:
|
|
320
|
+
await self._handle_error_response(response, endpoint, "POST multipart")
|
|
321
|
+
data = await response.json()
|
|
322
|
+
return data.get("message", data)
|
|
323
|
+
except (ARAuthenticationError, ARAPIError):
|
|
324
|
+
raise
|
|
325
|
+
except aiohttp.ServerTimeoutError as e:
|
|
326
|
+
self._log_error(f"POST multipart {endpoint} timeout: {e}")
|
|
327
|
+
raise ARTimeoutError(f"Request to {endpoint} timed out") from e
|
|
328
|
+
except aiohttp.ClientConnectorError as e:
|
|
329
|
+
self._log_error(f"POST multipart {endpoint} connection error: {e}")
|
|
330
|
+
raise ARConnectionError(f"Failed to connect to {endpoint}") from e
|
|
331
|
+
except aiohttp.ClientError as e:
|
|
332
|
+
self._log_error(f"POST multipart {endpoint} error: {e}")
|
|
333
|
+
raise ARAPIError(str(e)) from e
|
|
334
|
+
|
|
335
|
+
async def _request_delete(
|
|
336
|
+
self,
|
|
337
|
+
endpoint: str,
|
|
338
|
+
params: Dict[str, Any],
|
|
339
|
+
timeout: Optional[float] = None,
|
|
340
|
+
api_base: Optional[str] = None,
|
|
341
|
+
) -> Optional[Dict[str, Any]]:
|
|
342
|
+
"""Make authenticated async DELETE request."""
|
|
343
|
+
session = self._ensure_session()
|
|
344
|
+
url = f"{api_base}.{endpoint}" if api_base else self._build_endpoint_url(endpoint)
|
|
345
|
+
params = self._with_site_url(params)
|
|
346
|
+
headers = self._get_headers(params, for_query_string=True)
|
|
347
|
+
|
|
348
|
+
try:
|
|
349
|
+
timeout_obj = aiohttp.ClientTimeout(total=timeout or self.timeout)
|
|
350
|
+
async with session.delete(url, params=params, headers=headers, timeout=timeout_obj) as response:
|
|
351
|
+
await self._handle_error_response(response, endpoint, "DELETE")
|
|
352
|
+
data = await response.json()
|
|
353
|
+
return data.get("message", data)
|
|
354
|
+
except (ARAuthenticationError, ARAPIError):
|
|
355
|
+
raise
|
|
356
|
+
except aiohttp.ServerTimeoutError as e:
|
|
357
|
+
self._log_error(f"DELETE {endpoint} timeout: {e}")
|
|
358
|
+
raise ARTimeoutError(f"Request to {endpoint} timed out") from e
|
|
359
|
+
except aiohttp.ClientConnectorError as e:
|
|
360
|
+
self._log_error(f"DELETE {endpoint} connection error: {e}")
|
|
361
|
+
raise ARConnectionError(f"Failed to connect to {endpoint}") from e
|
|
362
|
+
except aiohttp.ClientError as e:
|
|
363
|
+
self._log_error(f"DELETE {endpoint} error: {e}")
|
|
364
|
+
raise ARAPIError(str(e)) from e
|
|
365
|
+
|
|
366
|
+
# =========================================================================
|
|
367
|
+
# Streaming API
|
|
368
|
+
# =========================================================================
|
|
369
|
+
|
|
370
|
+
async def stream_chat(
|
|
371
|
+
self,
|
|
372
|
+
session_id: str,
|
|
373
|
+
message: Optional[str],
|
|
374
|
+
user_id: str,
|
|
375
|
+
context: Optional[Dict[str, Any]] = None,
|
|
376
|
+
model_id: Optional[str] = None,
|
|
377
|
+
attachments: Optional[List[Dict[str, Any]]] = None,
|
|
378
|
+
system_prompt_addendum: Optional[str] = None,
|
|
379
|
+
client_type: Optional[str] = None,
|
|
380
|
+
interrupt_response: Optional[List[Dict[str, str]]] = None,
|
|
381
|
+
message_id: Optional[str] = None,
|
|
382
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
383
|
+
continue_from_message_id: Optional[str] = None,
|
|
384
|
+
*,
|
|
385
|
+
web_search: Optional[bool] = None,
|
|
386
|
+
thinking_enabled: Optional[bool] = None,
|
|
387
|
+
) -> AsyncGenerator[Dict[str, Any], None]:
|
|
388
|
+
"""Async version of AssistantRuntimeClient.stream_chat.
|
|
389
|
+
|
|
390
|
+
On ``stream_complete``, ``event['session_state']`` is the updated signed
|
|
391
|
+
blob — store it and pass it as ``session_state`` on the next turn.
|
|
392
|
+
"""
|
|
393
|
+
session = self._ensure_session()
|
|
394
|
+
payload = self._prepare_stream_payload(
|
|
395
|
+
session_id, message, user_id, context, model_id, attachments,
|
|
396
|
+
system_prompt_addendum, client_type=client_type,
|
|
397
|
+
interrupt_response=interrupt_response,
|
|
398
|
+
message_id=message_id,
|
|
399
|
+
session_state=session_state,
|
|
400
|
+
continue_from_message_id=continue_from_message_id,
|
|
401
|
+
web_search=web_search,
|
|
402
|
+
thinking_enabled=thinking_enabled,
|
|
403
|
+
)
|
|
404
|
+
url = self._build_endpoint_url("streaming.stream_chat")
|
|
405
|
+
payload = self._with_site_url(payload)
|
|
406
|
+
headers = self._get_stream_headers(payload, for_json_body=True)
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
timeout = aiohttp.ClientTimeout(
|
|
410
|
+
connect=self.STREAM_CONNECT_TIMEOUT,
|
|
411
|
+
total=self.STREAM_READ_TIMEOUT,
|
|
412
|
+
)
|
|
413
|
+
async with session.post(url, json=payload, headers=headers, timeout=timeout) as response:
|
|
414
|
+
response.raise_for_status()
|
|
415
|
+
|
|
416
|
+
current_event = None
|
|
417
|
+
|
|
418
|
+
async for line in response.content:
|
|
419
|
+
if not line:
|
|
420
|
+
continue
|
|
421
|
+
|
|
422
|
+
line_str = line.decode("utf-8").strip()
|
|
423
|
+
if not line_str:
|
|
424
|
+
continue
|
|
425
|
+
|
|
426
|
+
parsed = self._parse_sse_line(line_str)
|
|
427
|
+
if not parsed:
|
|
428
|
+
continue
|
|
429
|
+
|
|
430
|
+
if parsed["type"] == "heartbeat":
|
|
431
|
+
yield {"event": "heartbeat", "data": {}}
|
|
432
|
+
continue
|
|
433
|
+
if parsed["type"] == "event_name":
|
|
434
|
+
current_event = parsed["value"]
|
|
435
|
+
elif parsed["type"] == "data":
|
|
436
|
+
yield {"event": current_event or "unknown", "data": parsed["value"]}
|
|
437
|
+
current_event = None
|
|
438
|
+
|
|
439
|
+
except aiohttp.ServerTimeoutError:
|
|
440
|
+
yield {
|
|
441
|
+
"event": "stream_error",
|
|
442
|
+
"data": {"error": "Connection timeout", "error_code": "TIMEOUT"},
|
|
443
|
+
}
|
|
444
|
+
except aiohttp.ClientError as e:
|
|
445
|
+
yield {
|
|
446
|
+
"event": "stream_error",
|
|
447
|
+
"data": {"error": str(e), "error_code": "REQUEST_ERROR"},
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
# =========================================================================
|
|
451
|
+
# Tenant APIs
|
|
452
|
+
# =========================================================================
|
|
453
|
+
|
|
454
|
+
async def get_tenant_info(self) -> Optional[Dict[str, Any]]:
|
|
455
|
+
"""Async version of AssistantRuntimeClient.get_tenant_info."""
|
|
456
|
+
endpoint, params = self._prepare_get_tenant_info()
|
|
457
|
+
return await self._request_get(endpoint, params)
|
|
458
|
+
|
|
459
|
+
async def accept_terms(self, terms_version: str, accepted_by: str) -> Dict[str, Any]:
|
|
460
|
+
"""Async version of AssistantRuntimeClient.accept_terms."""
|
|
461
|
+
endpoint, payload = self._prepare_accept_terms(terms_version, accepted_by)
|
|
462
|
+
return await self._request_post_json(endpoint, payload)
|
|
463
|
+
|
|
464
|
+
# =========================================================================
|
|
465
|
+
# Model APIs
|
|
466
|
+
# =========================================================================
|
|
467
|
+
|
|
468
|
+
async def list_available_models(self, timeout: Optional[float] = None) -> Optional[Dict[str, Any]]:
|
|
469
|
+
"""Async version of AssistantRuntimeClient.list_available_models."""
|
|
470
|
+
endpoint, params = self._prepare_list_available_models()
|
|
471
|
+
return await self._request_get(endpoint, params, timeout=timeout)
|
|
472
|
+
|
|
473
|
+
async def get_available_models(self) -> Optional[Dict[str, Any]]:
|
|
474
|
+
"""Async version of AssistantRuntimeClient.get_available_models."""
|
|
475
|
+
endpoint, params = self._prepare_get_available_models()
|
|
476
|
+
return await self._request_get(endpoint, params)
|
|
477
|
+
|
|
478
|
+
async def set_preferred_model(self, model_id: str) -> bool:
|
|
479
|
+
"""Async version of AssistantRuntimeClient.set_preferred_model."""
|
|
480
|
+
endpoint, payload = self._prepare_set_preferred_model(model_id)
|
|
481
|
+
result = await self._request_post_json(endpoint, payload)
|
|
482
|
+
return result.get("success", False) if result else False
|
|
483
|
+
|
|
484
|
+
# =========================================================================
|
|
485
|
+
# Origin Binding APIs (Phase 2)
|
|
486
|
+
# =========================================================================
|
|
487
|
+
|
|
488
|
+
async def request_rebind(self, new_site_url: str) -> Dict[str, Any]:
|
|
489
|
+
"""Initiate a tenant rebind. Returns {"rebind_token": str, "expires_at": str}.
|
|
490
|
+
|
|
491
|
+
When the site URL of an installation changes, call this to begin the
|
|
492
|
+
rebind flow. AR sends a confirmation email to the tenant owner. After
|
|
493
|
+
the owner clicks the link, call the module-level helper
|
|
494
|
+
``get_rotated_secret(ar_url, rebind_token)`` in the sync client with
|
|
495
|
+
the token from the link to retrieve the new ``tenant_secret``.
|
|
496
|
+
"""
|
|
497
|
+
return await self._request_post_json(
|
|
498
|
+
"request_rebind",
|
|
499
|
+
{"tenant_id": self.tenant_id, "new_site_url": new_site_url},
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
async def claim_tenant_email(self, owner_email: str) -> Dict[str, Any]:
|
|
503
|
+
"""Bootstrap an owner_email on a legacy tenant (one without a verified
|
|
504
|
+
owner_email on file). AR sends a verification email; the email is only
|
|
505
|
+
persisted to the tenant record after the owner clicks the link.
|
|
506
|
+
"""
|
|
507
|
+
return await self._request_post_json(
|
|
508
|
+
"claim_tenant_email",
|
|
509
|
+
{"tenant_id": self.tenant_id, "owner_email": owner_email},
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
async def diagnose_registration(self) -> Dict[str, Any]:
|
|
513
|
+
"""Diagnose registration issues. Returns one of:
|
|
514
|
+
|
|
515
|
+
- ``{"status": "ok", "bound_host": ..., "last_verification": ...}``
|
|
516
|
+
- ``{"status": "origin_mismatch", "bound_host": ..., "claimed_host": ...,
|
|
517
|
+
"remediation": "rebind", "rebind_url": ...}``
|
|
518
|
+
"""
|
|
519
|
+
return await self._request_post_json(
|
|
520
|
+
"diagnose_registration",
|
|
521
|
+
{"tenant_id": self.tenant_id},
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
# =========================================================================
|
|
525
|
+
# Prompt APIs
|
|
526
|
+
# =========================================================================
|
|
527
|
+
|
|
528
|
+
async def list_prompts(self, user_id: str, cursor: Optional[str] = None, timeout: Optional[float] = None) -> Optional[Dict[str, Any]]:
|
|
529
|
+
"""Async version of AssistantRuntimeClient.list_prompts."""
|
|
530
|
+
endpoint, params = self._prepare_list_prompts(user_id, cursor)
|
|
531
|
+
return await self._request_get(endpoint, params, timeout=timeout)
|
|
532
|
+
|
|
533
|
+
async def get_prompt(
|
|
534
|
+
self,
|
|
535
|
+
prompt_name: str,
|
|
536
|
+
user_id: str,
|
|
537
|
+
arguments: Optional[Dict[str, Any]] = None,
|
|
538
|
+
) -> Optional[Dict[str, Any]]:
|
|
539
|
+
"""Async version of AssistantRuntimeClient.get_prompt."""
|
|
540
|
+
endpoint, payload = self._prepare_get_prompt(prompt_name, user_id, arguments)
|
|
541
|
+
return await self._request_post_json(endpoint, payload)
|
|
542
|
+
|
|
543
|
+
# =========================================================================
|
|
544
|
+
# Suggestion APIs
|
|
545
|
+
# =========================================================================
|
|
546
|
+
|
|
547
|
+
async def get_suggestions(
|
|
548
|
+
self,
|
|
549
|
+
user_id: str,
|
|
550
|
+
context: Optional[Dict[str, Any]] = None,
|
|
551
|
+
limit: int = 8,
|
|
552
|
+
timeout: Optional[float] = None,
|
|
553
|
+
) -> Optional[Dict[str, Any]]:
|
|
554
|
+
"""Async version of AssistantRuntimeClient.get_suggestions."""
|
|
555
|
+
endpoint, params = self._prepare_get_suggestions(user_id, context, limit)
|
|
556
|
+
return await self._request_get(endpoint, params, timeout=timeout)
|
|
557
|
+
|
|
558
|
+
async def generate_curated_suggestions(
|
|
559
|
+
self,
|
|
560
|
+
user_id: str,
|
|
561
|
+
signals: Optional[Dict[str, Any]] = None,
|
|
562
|
+
timeout: Optional[float] = None,
|
|
563
|
+
) -> Optional[Dict[str, Any]]:
|
|
564
|
+
"""Generate LLM-curated welcome suggestions from usage signals.
|
|
565
|
+
|
|
566
|
+
Costs one Economy-tier completion on AR (rate-limited server-side to
|
|
567
|
+
one generation per user per 20h). Returns
|
|
568
|
+
{"suggestions": [...], "generated_at": ...} or an empty-suggestions
|
|
569
|
+
dict with a reason/rate_limited flag.
|
|
570
|
+
"""
|
|
571
|
+
endpoint, payload = self._prepare_generate_curated_suggestions(user_id, signals)
|
|
572
|
+
return await self._request_post_json(endpoint, payload, timeout=timeout)
|
|
573
|
+
|
|
574
|
+
# =========================================================================
|
|
575
|
+
# Onboarding APIs
|
|
576
|
+
# =========================================================================
|
|
577
|
+
|
|
578
|
+
async def get_onboarding_status(self, user_id: str) -> Optional[Dict[str, Any]]:
|
|
579
|
+
"""Async version of AssistantRuntimeClient.get_onboarding_status."""
|
|
580
|
+
endpoint, params = self._prepare_get_onboarding_status(user_id)
|
|
581
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
582
|
+
|
|
583
|
+
async def complete_onboarding(
|
|
584
|
+
self,
|
|
585
|
+
user_id: str,
|
|
586
|
+
) -> Optional[Dict[str, Any]]:
|
|
587
|
+
"""Async version of AssistantRuntimeClient.complete_onboarding."""
|
|
588
|
+
endpoint, payload = self._prepare_complete_onboarding(user_id)
|
|
589
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
590
|
+
|
|
591
|
+
# =========================================================================
|
|
592
|
+
# Document APIs (RAG)
|
|
593
|
+
# =========================================================================
|
|
594
|
+
|
|
595
|
+
async def upload_document(
|
|
596
|
+
self,
|
|
597
|
+
file_path: Optional[str] = None,
|
|
598
|
+
file_data: Optional[bytes] = None,
|
|
599
|
+
file_name: Optional[str] = None,
|
|
600
|
+
content_type: Optional[str] = None,
|
|
601
|
+
user_id: Optional[str] = None,
|
|
602
|
+
visibility: Optional[str] = None,
|
|
603
|
+
shared_with: Optional[List[str]] = None,
|
|
604
|
+
) -> Optional[Dict[str, Any]]:
|
|
605
|
+
"""Async version of AssistantRuntimeClient.upload_document."""
|
|
606
|
+
endpoint, params, f_field, f_name, f_data, c_type = self._prepare_upload_document(
|
|
607
|
+
file_path, file_data, file_name, content_type,
|
|
608
|
+
user_id=user_id, visibility=visibility, shared_with=shared_with,
|
|
609
|
+
)
|
|
610
|
+
return await self._request_post_multipart(
|
|
611
|
+
endpoint, params=params, file_field=f_field,
|
|
612
|
+
file_name=f_name, file_data=f_data, content_type=c_type,
|
|
613
|
+
timeout=120.0, api_base=self.memory_api_base,
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
async def list_documents(
|
|
617
|
+
self, limit: int = 50, offset: int = 0, user_id: Optional[str] = None
|
|
618
|
+
) -> Optional[Dict[str, Any]]:
|
|
619
|
+
"""Async version of AssistantRuntimeClient.list_documents."""
|
|
620
|
+
endpoint, params = self._prepare_list_documents(limit, offset, user_id=user_id)
|
|
621
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
622
|
+
|
|
623
|
+
async def get_document(self, document_id: str) -> Optional[Dict[str, Any]]:
|
|
624
|
+
"""Async version of AssistantRuntimeClient.get_document."""
|
|
625
|
+
endpoint, params = self._prepare_get_document(document_id)
|
|
626
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
627
|
+
|
|
628
|
+
async def list_chunks(
|
|
629
|
+
self,
|
|
630
|
+
document_id: str,
|
|
631
|
+
user_id: Optional[str] = None,
|
|
632
|
+
search: Optional[str] = None,
|
|
633
|
+
limit: int = 50,
|
|
634
|
+
offset: int = 0,
|
|
635
|
+
) -> Optional[Dict[str, Any]]:
|
|
636
|
+
"""Async version of AssistantRuntimeClient.list_chunks."""
|
|
637
|
+
endpoint, params = self._prepare_list_chunks(
|
|
638
|
+
document_id, user_id=user_id, search=search, limit=limit, offset=offset
|
|
639
|
+
)
|
|
640
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
641
|
+
|
|
642
|
+
async def get_document_content(
|
|
643
|
+
self, document_id: str, user_id: Optional[str] = None
|
|
644
|
+
) -> tuple:
|
|
645
|
+
"""Async version of AssistantRuntimeClient.get_document_content."""
|
|
646
|
+
endpoint, params = self._prepare_get_document_content(document_id, user_id=user_id)
|
|
647
|
+
return await self._request_get_raw(endpoint, params, api_base=self.memory_api_base)
|
|
648
|
+
|
|
649
|
+
async def delete_document(
|
|
650
|
+
self, document_id: str, user_id: Optional[str] = None
|
|
651
|
+
) -> Optional[Dict[str, Any]]:
|
|
652
|
+
"""Async version of AssistantRuntimeClient.delete_document."""
|
|
653
|
+
endpoint, payload = self._prepare_delete_document(document_id, user_id=user_id)
|
|
654
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
655
|
+
|
|
656
|
+
async def update_document_access(
|
|
657
|
+
self,
|
|
658
|
+
document_id: str,
|
|
659
|
+
user_id: str,
|
|
660
|
+
visibility: Optional[str] = None,
|
|
661
|
+
add_users: Optional[List[str]] = None,
|
|
662
|
+
remove_users: Optional[List[str]] = None,
|
|
663
|
+
) -> Optional[Dict[str, Any]]:
|
|
664
|
+
"""Async version of AssistantRuntimeClient.update_document_access."""
|
|
665
|
+
endpoint, payload = self._prepare_update_document_access(
|
|
666
|
+
document_id, user_id,
|
|
667
|
+
visibility=visibility, add_users=add_users, remove_users=remove_users,
|
|
668
|
+
)
|
|
669
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
670
|
+
|
|
671
|
+
async def get_storage_info(self) -> Optional[Dict[str, Any]]:
|
|
672
|
+
"""Async version of AssistantRuntimeClient.get_storage_info."""
|
|
673
|
+
endpoint, params = self._prepare_get_storage_info()
|
|
674
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
675
|
+
|
|
676
|
+
# =========================================================================
|
|
677
|
+
# Memory APIs (User Memory Viewer)
|
|
678
|
+
# =========================================================================
|
|
679
|
+
|
|
680
|
+
async def list_memories(
|
|
681
|
+
self,
|
|
682
|
+
user_id: Optional[str] = None,
|
|
683
|
+
memory_type: Optional[str] = None,
|
|
684
|
+
limit: int = 50,
|
|
685
|
+
offset: int = 0,
|
|
686
|
+
) -> Optional[Dict[str, Any]]:
|
|
687
|
+
"""Async version of AssistantRuntimeClient.list_memories."""
|
|
688
|
+
endpoint, params = self._prepare_list_memories(user_id, memory_type, limit, offset)
|
|
689
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
690
|
+
|
|
691
|
+
async def delete_memory(self, user_id: str, memory_id: str) -> Optional[Dict[str, Any]]:
|
|
692
|
+
"""Async version of AssistantRuntimeClient.delete_memory."""
|
|
693
|
+
endpoint, payload = self._prepare_delete_memory(user_id, memory_id)
|
|
694
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
695
|
+
|
|
696
|
+
async def delete_all_memories(self, user_id: str) -> Optional[Dict[str, Any]]:
|
|
697
|
+
"""Async version of AssistantRuntimeClient.delete_all_memories."""
|
|
698
|
+
endpoint, payload = self._prepare_delete_all_memories(user_id)
|
|
699
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
700
|
+
|
|
701
|
+
async def update_memory(self, user_id: str, memory_id: str, content: str) -> Optional[Dict[str, Any]]:
|
|
702
|
+
"""Async version of AssistantRuntimeClient.update_memory."""
|
|
703
|
+
endpoint, payload = self._prepare_update_memory(user_id, memory_id, content)
|
|
704
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
705
|
+
|
|
706
|
+
async def get_memory_stats(self, user_id: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
707
|
+
"""Async version of AssistantRuntimeClient.get_memory_stats."""
|
|
708
|
+
endpoint, params = self._prepare_get_memory_stats(user_id)
|
|
709
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
710
|
+
|
|
711
|
+
async def get_memory_summary(
|
|
712
|
+
self,
|
|
713
|
+
user_id: str,
|
|
714
|
+
force: bool = False,
|
|
715
|
+
timeout: Optional[float] = None,
|
|
716
|
+
) -> Optional[Dict[str, Any]]:
|
|
717
|
+
"""Async get AI-generated narrative summary of user's memories."""
|
|
718
|
+
endpoint, params = self._prepare_get_memory_summary(user_id, force)
|
|
719
|
+
return await self._request_get(endpoint, params, timeout=timeout, api_base=self.memory_api_base)
|
|
720
|
+
|
|
721
|
+
# =========================================================================
|
|
722
|
+
# Shared Knowledge APIs
|
|
723
|
+
# =========================================================================
|
|
724
|
+
|
|
725
|
+
async def get_shared_knowledge(self) -> Optional[Dict[str, Any]]:
|
|
726
|
+
"""Async version of AssistantRuntimeClient.get_shared_knowledge."""
|
|
727
|
+
endpoint, params = self._prepare_get_shared_knowledge()
|
|
728
|
+
return await self._request_get(endpoint, params, api_base=self.memory_api_base)
|
|
729
|
+
|
|
730
|
+
async def update_shared_knowledge(self, content: str) -> Optional[Dict[str, Any]]:
|
|
731
|
+
"""Async version of AssistantRuntimeClient.update_shared_knowledge."""
|
|
732
|
+
endpoint, payload = self._prepare_update_shared_knowledge(content)
|
|
733
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
734
|
+
|
|
735
|
+
async def share_memory_to_knowledge(self, user_id: str, memory_id: str) -> Optional[Dict[str, Any]]:
|
|
736
|
+
"""Async version of AssistantRuntimeClient.share_memory_to_knowledge."""
|
|
737
|
+
endpoint, payload = self._prepare_share_memory_to_knowledge(user_id, memory_id)
|
|
738
|
+
return await self._request_post_json(endpoint, payload, api_base=self.memory_api_base)
|
|
739
|
+
|
|
740
|
+
# =========================================================================
|
|
741
|
+
# Resource APIs (Skills/Documentation)
|
|
742
|
+
# =========================================================================
|
|
743
|
+
|
|
744
|
+
async def list_resources(
|
|
745
|
+
self,
|
|
746
|
+
user_id: str,
|
|
747
|
+
server: Optional[str] = None,
|
|
748
|
+
) -> Optional[Dict[str, Any]]:
|
|
749
|
+
"""Async version of AssistantRuntimeClient.list_resources."""
|
|
750
|
+
params = self._prepare_resource_params(user_id, server=server)
|
|
751
|
+
return await self._request_get("resources.list_resources", params)
|
|
752
|
+
|
|
753
|
+
async def read_resource(self, user_id: str, uri: str) -> Optional[Dict[str, Any]]:
|
|
754
|
+
"""Async version of AssistantRuntimeClient.read_resource."""
|
|
755
|
+
params = self._prepare_resource_params(user_id, uri=uri)
|
|
756
|
+
return await self._request_post_json("resources.read_resource", params)
|
|
757
|
+
|
|
758
|
+
# =========================================================================
|
|
759
|
+
# Tool APIs
|
|
760
|
+
# =========================================================================
|
|
761
|
+
|
|
762
|
+
async def list_tools(
|
|
763
|
+
self,
|
|
764
|
+
user_id: str,
|
|
765
|
+
server: Optional[str] = None,
|
|
766
|
+
) -> Optional[Dict[str, Any]]:
|
|
767
|
+
"""Async version of AssistantRuntimeClient.list_tools."""
|
|
768
|
+
endpoint, params = self._prepare_list_tools(user_id, server)
|
|
769
|
+
return await self._request_get(endpoint, params)
|
|
770
|
+
|
|
771
|
+
# =========================================================================
|
|
772
|
+
# Tool Preference APIs (per-user approval settings)
|
|
773
|
+
# =========================================================================
|
|
774
|
+
|
|
775
|
+
async def list_tool_preferences(self, user_id: str) -> Optional[Dict[str, Any]]:
|
|
776
|
+
"""Async version of AssistantRuntimeClient.list_tool_preferences."""
|
|
777
|
+
endpoint, params = self._prepare_list_tool_preferences(user_id)
|
|
778
|
+
return await self._request_get(endpoint, params)
|
|
779
|
+
|
|
780
|
+
async def set_tool_preference(
|
|
781
|
+
self,
|
|
782
|
+
user_id: str,
|
|
783
|
+
tool_name: str,
|
|
784
|
+
preference: str,
|
|
785
|
+
) -> Optional[Dict[str, Any]]:
|
|
786
|
+
"""Async version of AssistantRuntimeClient.set_tool_preference."""
|
|
787
|
+
endpoint, payload = self._prepare_set_tool_preference(user_id, tool_name, preference)
|
|
788
|
+
return await self._request_post_json(endpoint, payload)
|
|
789
|
+
|
|
790
|
+
# =========================================================================
|
|
791
|
+
# Billing & Subscription APIs
|
|
792
|
+
# =========================================================================
|
|
793
|
+
|
|
794
|
+
async def check_billing_available(self) -> bool:
|
|
795
|
+
"""Async version of AssistantRuntimeClient.check_billing_available."""
|
|
796
|
+
session = self._ensure_session()
|
|
797
|
+
try:
|
|
798
|
+
url = f"{self.api_base}.get_capabilities"
|
|
799
|
+
timeout_obj = aiohttp.ClientTimeout(total=self.timeout)
|
|
800
|
+
async with session.get(url, timeout=timeout_obj) as response:
|
|
801
|
+
response.raise_for_status()
|
|
802
|
+
data = await response.json()
|
|
803
|
+
result = data.get("message", data)
|
|
804
|
+
self._billing_available = result.get("billing_enabled", False)
|
|
805
|
+
except (aiohttp.ClientError, Exception):
|
|
806
|
+
self._billing_available = False
|
|
807
|
+
return self._billing_available
|
|
808
|
+
|
|
809
|
+
async def get_plan_comparison(self) -> Optional[Dict[str, Any]]:
|
|
810
|
+
"""Async version of AssistantRuntimeClient.get_plan_comparison."""
|
|
811
|
+
self._require_billing()
|
|
812
|
+
session = self._ensure_session()
|
|
813
|
+
url = self._build_billing_endpoint_url("get_plan_comparison")
|
|
814
|
+
try:
|
|
815
|
+
timeout_obj = aiohttp.ClientTimeout(total=self.timeout)
|
|
816
|
+
async with session.get(url, timeout=timeout_obj) as response:
|
|
817
|
+
response.raise_for_status()
|
|
818
|
+
data = await response.json()
|
|
819
|
+
return data.get("message", data)
|
|
820
|
+
except (aiohttp.ClientError, Exception) as e:
|
|
821
|
+
self._log_error(f"get_plan_comparison error: {e}")
|
|
822
|
+
return None
|
|
823
|
+
|
|
824
|
+
async def get_recommended_gateway(self) -> Optional[Dict[str, Any]]:
|
|
825
|
+
"""Async version of AssistantRuntimeClient.get_recommended_gateway."""
|
|
826
|
+
endpoint, params = self._prepare_get_recommended_gateway()
|
|
827
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
828
|
+
|
|
829
|
+
async def get_available_gateways(self) -> Optional[Dict[str, Any]]:
|
|
830
|
+
"""Async version of AssistantRuntimeClient.get_available_gateways."""
|
|
831
|
+
endpoint, params = self._prepare_get_available_gateways()
|
|
832
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
833
|
+
|
|
834
|
+
async def preview_plan_pricing(
|
|
835
|
+
self, plan: str, billing_cycle: str = "monthly",
|
|
836
|
+
) -> Optional[Dict[str, Any]]:
|
|
837
|
+
"""Async version of AssistantRuntimeClient.preview_plan_pricing."""
|
|
838
|
+
endpoint, params = self._prepare_preview_plan_pricing(plan, billing_cycle)
|
|
839
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
840
|
+
|
|
841
|
+
async def add_user_seat(self) -> Optional[Dict[str, Any]]:
|
|
842
|
+
"""Async version of AssistantRuntimeClient.add_user_seat."""
|
|
843
|
+
endpoint, params = self._prepare_add_user_seat()
|
|
844
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
845
|
+
|
|
846
|
+
async def remove_user_seat(self) -> Optional[Dict[str, Any]]:
|
|
847
|
+
"""Async version of AssistantRuntimeClient.remove_user_seat."""
|
|
848
|
+
endpoint, params = self._prepare_remove_user_seat()
|
|
849
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
850
|
+
|
|
851
|
+
async def preview_seat_charge(self) -> Optional[Dict[str, Any]]:
|
|
852
|
+
"""Async version of AssistantRuntimeClient.preview_seat_charge."""
|
|
853
|
+
endpoint, params = self._prepare_preview_seat_charge()
|
|
854
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
855
|
+
|
|
856
|
+
async def download_invoice_pdf(self, ar_invoice_name: str) -> tuple:
|
|
857
|
+
"""Async version of AssistantRuntimeClient.download_invoice_pdf."""
|
|
858
|
+
endpoint, params = self._prepare_download_invoice_pdf(ar_invoice_name)
|
|
859
|
+
return await self._request_get_raw(
|
|
860
|
+
endpoint, params, api_base=self.billing_api_base,
|
|
861
|
+
)
|
|
862
|
+
|
|
863
|
+
async def initiate_checkout(
|
|
864
|
+
self,
|
|
865
|
+
plan: str,
|
|
866
|
+
billing_cycle: str = "monthly",
|
|
867
|
+
gateway: Optional[str] = None,
|
|
868
|
+
billing_name: Optional[str] = None,
|
|
869
|
+
billing_email: Optional[str] = None,
|
|
870
|
+
) -> Optional[Dict[str, Any]]:
|
|
871
|
+
"""Async version of AssistantRuntimeClient.initiate_checkout."""
|
|
872
|
+
endpoint, payload = self._prepare_initiate_checkout(plan, billing_cycle, gateway, billing_name, billing_email)
|
|
873
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
874
|
+
|
|
875
|
+
async def verify_checkout(self, session_id: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
876
|
+
"""Async version of AssistantRuntimeClient.verify_checkout."""
|
|
877
|
+
endpoint, payload = self._prepare_verify_checkout(session_id)
|
|
878
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
879
|
+
|
|
880
|
+
async def verify_razorpay_payment(
|
|
881
|
+
self,
|
|
882
|
+
razorpay_payment_id: str,
|
|
883
|
+
razorpay_subscription_id: str,
|
|
884
|
+
razorpay_signature: str,
|
|
885
|
+
) -> Optional[Dict[str, Any]]:
|
|
886
|
+
"""Async version of AssistantRuntimeClient.verify_razorpay_payment."""
|
|
887
|
+
endpoint, payload = self._prepare_verify_razorpay_payment(razorpay_payment_id, razorpay_subscription_id, razorpay_signature)
|
|
888
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
889
|
+
|
|
890
|
+
async def verify_razorpay_credit_payment(
|
|
891
|
+
self,
|
|
892
|
+
razorpay_payment_id: str,
|
|
893
|
+
razorpay_order_id: str,
|
|
894
|
+
razorpay_signature: str,
|
|
895
|
+
) -> Optional[Dict[str, Any]]:
|
|
896
|
+
"""Async version of AssistantRuntimeClient.verify_razorpay_credit_payment."""
|
|
897
|
+
endpoint, payload = self._prepare_verify_razorpay_credit_payment(razorpay_payment_id, razorpay_order_id, razorpay_signature)
|
|
898
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
899
|
+
|
|
900
|
+
async def verify_seat_payment(
|
|
901
|
+
self,
|
|
902
|
+
razorpay_payment_id: str,
|
|
903
|
+
razorpay_order_id: str,
|
|
904
|
+
razorpay_signature: str,
|
|
905
|
+
) -> Optional[Dict[str, Any]]:
|
|
906
|
+
"""Async version of AssistantRuntimeClient.verify_seat_payment."""
|
|
907
|
+
endpoint, payload = self._prepare_verify_seat_payment(
|
|
908
|
+
razorpay_payment_id, razorpay_order_id, razorpay_signature
|
|
909
|
+
)
|
|
910
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
911
|
+
|
|
912
|
+
async def get_token_analytics(self, days: int = 30, user_id: str = None) -> Optional[Dict[str, Any]]:
|
|
913
|
+
"""Async version of AssistantRuntimeClient.get_token_analytics."""
|
|
914
|
+
endpoint, payload = self._prepare_get_token_analytics(days, user_id)
|
|
915
|
+
return await self._request_post_json(endpoint, payload)
|
|
916
|
+
|
|
917
|
+
async def get_conversation_analytics(
|
|
918
|
+
self, user_id: str = None, days: int = 30, limit: int = 50, offset: int = 0,
|
|
919
|
+
) -> Optional[Dict[str, Any]]:
|
|
920
|
+
"""Async version of AssistantRuntimeClient.get_conversation_analytics."""
|
|
921
|
+
endpoint, payload = self._prepare_get_conversation_analytics(user_id, days, limit, offset)
|
|
922
|
+
return await self._request_post_json(endpoint, payload)
|
|
923
|
+
|
|
924
|
+
async def get_message_credits(self, conversation_id: str, user_id: str = None) -> Optional[Dict[str, Any]]:
|
|
925
|
+
"""Async version of AssistantRuntimeClient.get_message_credits."""
|
|
926
|
+
endpoint, payload = self._prepare_get_message_credits(conversation_id, user_id)
|
|
927
|
+
return await self._request_post_json(endpoint, payload)
|
|
928
|
+
|
|
929
|
+
async def get_usage_dashboard(self) -> Optional[Dict[str, Any]]:
|
|
930
|
+
"""Async version of AssistantRuntimeClient.get_usage_dashboard."""
|
|
931
|
+
endpoint, payload = self._prepare_get_usage_dashboard()
|
|
932
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
933
|
+
|
|
934
|
+
async def get_usage_history(self, days: int = 30) -> Optional[Dict[str, Any]]:
|
|
935
|
+
"""Async version of AssistantRuntimeClient.get_usage_history."""
|
|
936
|
+
endpoint, payload = self._prepare_get_usage_history(days)
|
|
937
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
938
|
+
|
|
939
|
+
async def get_invoices(self, limit: int = 10) -> Optional[Dict[str, Any]]:
|
|
940
|
+
"""Async version of AssistantRuntimeClient.get_invoices."""
|
|
941
|
+
endpoint, payload = self._prepare_get_invoices(limit)
|
|
942
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
943
|
+
|
|
944
|
+
async def get_upcoming_invoice(self) -> Optional[Dict[str, Any]]:
|
|
945
|
+
"""Async version of AssistantRuntimeClient.get_upcoming_invoice."""
|
|
946
|
+
endpoint, payload = self._prepare_get_upcoming_invoice()
|
|
947
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
948
|
+
|
|
949
|
+
async def get_payment_methods(self) -> Optional[Dict[str, Any]]:
|
|
950
|
+
"""Async version of AssistantRuntimeClient.get_payment_methods."""
|
|
951
|
+
endpoint, payload = self._prepare_get_payment_methods()
|
|
952
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
953
|
+
|
|
954
|
+
async def upgrade_plan(
|
|
955
|
+
self,
|
|
956
|
+
new_plan: str,
|
|
957
|
+
billing_cycle: str = "monthly",
|
|
958
|
+
gateway: Optional[str] = None,
|
|
959
|
+
billing_name: Optional[str] = None,
|
|
960
|
+
billing_email: Optional[str] = None,
|
|
961
|
+
promo_code: Optional[str] = None,
|
|
962
|
+
payment_method: Optional[str] = None,
|
|
963
|
+
) -> Optional[Dict[str, Any]]:
|
|
964
|
+
"""Async version of AssistantRuntimeClient.upgrade_plan."""
|
|
965
|
+
endpoint, payload = self._prepare_upgrade_plan(
|
|
966
|
+
new_plan, billing_cycle, gateway, billing_name, billing_email, promo_code,
|
|
967
|
+
payment_method=payment_method,
|
|
968
|
+
)
|
|
969
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
970
|
+
|
|
971
|
+
async def reauthorize_mandate(
|
|
972
|
+
self,
|
|
973
|
+
billing_name: Optional[str] = None,
|
|
974
|
+
payment_method: Optional[str] = None,
|
|
975
|
+
) -> Optional[Dict[str, Any]]:
|
|
976
|
+
"""Async version of AssistantRuntimeClient.reauthorize_mandate."""
|
|
977
|
+
endpoint, payload = self._prepare_reauthorize_mandate(
|
|
978
|
+
billing_name=billing_name,
|
|
979
|
+
payment_method=payment_method,
|
|
980
|
+
)
|
|
981
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
982
|
+
|
|
983
|
+
async def validate_promo_code(
|
|
984
|
+
self,
|
|
985
|
+
promo_code: str,
|
|
986
|
+
plan: Optional[str] = None,
|
|
987
|
+
timeout: Optional[float] = None,
|
|
988
|
+
) -> Optional[Dict[str, Any]]:
|
|
989
|
+
"""Async validate a promo code for this tenant."""
|
|
990
|
+
endpoint, payload = self._prepare_validate_promo_code(promo_code, plan)
|
|
991
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base, timeout=timeout)
|
|
992
|
+
|
|
993
|
+
async def downgrade_to_free(self) -> Optional[Dict[str, Any]]:
|
|
994
|
+
"""Async version of AssistantRuntimeClient.downgrade_to_free."""
|
|
995
|
+
endpoint, payload = self._prepare_downgrade_to_free()
|
|
996
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
997
|
+
|
|
998
|
+
async def cancel_scheduled_change(self) -> Optional[Dict[str, Any]]:
|
|
999
|
+
"""Async version of AssistantRuntimeClient.cancel_scheduled_change."""
|
|
1000
|
+
endpoint, payload = self._prepare_cancel_scheduled_change()
|
|
1001
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1002
|
+
|
|
1003
|
+
async def cancel_subscription(self, cancel_immediately: bool = False) -> Optional[Dict[str, Any]]:
|
|
1004
|
+
"""Async version of AssistantRuntimeClient.cancel_subscription."""
|
|
1005
|
+
endpoint, payload = self._prepare_cancel_subscription(cancel_immediately)
|
|
1006
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1007
|
+
|
|
1008
|
+
async def reactivate_subscription(self) -> Optional[Dict[str, Any]]:
|
|
1009
|
+
"""Async version of AssistantRuntimeClient.reactivate_subscription."""
|
|
1010
|
+
endpoint, payload = self._prepare_reactivate_subscription()
|
|
1011
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1012
|
+
|
|
1013
|
+
async def pause_subscription(self) -> Optional[Dict[str, Any]]:
|
|
1014
|
+
"""Async version of AssistantRuntimeClient.pause_subscription."""
|
|
1015
|
+
endpoint, payload = self._prepare_pause_subscription()
|
|
1016
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1017
|
+
|
|
1018
|
+
async def resume_subscription(self) -> Optional[Dict[str, Any]]:
|
|
1019
|
+
"""Async version of AssistantRuntimeClient.resume_subscription."""
|
|
1020
|
+
endpoint, payload = self._prepare_resume_subscription()
|
|
1021
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1022
|
+
|
|
1023
|
+
async def update_payment_method(self) -> Optional[Dict[str, Any]]:
|
|
1024
|
+
"""Async version of AssistantRuntimeClient.update_payment_method."""
|
|
1025
|
+
endpoint, payload = self._prepare_update_payment_method()
|
|
1026
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1027
|
+
|
|
1028
|
+
async def get_subscription_status(self) -> Optional[Dict[str, Any]]:
|
|
1029
|
+
"""Async version of AssistantRuntimeClient.get_subscription_status."""
|
|
1030
|
+
endpoint, params = self._prepare_get_subscription_status()
|
|
1031
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
1032
|
+
|
|
1033
|
+
async def get_billing_history(self, limit: int = 20) -> Optional[Dict[str, Any]]:
|
|
1034
|
+
"""Async version of AssistantRuntimeClient.get_billing_history."""
|
|
1035
|
+
endpoint, params = self._prepare_get_billing_history(limit)
|
|
1036
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
1037
|
+
|
|
1038
|
+
async def get_billing_details(self) -> Optional[Dict[str, Any]]:
|
|
1039
|
+
"""Async version of AssistantRuntimeClient.get_billing_details."""
|
|
1040
|
+
endpoint, params = self._prepare_get_billing_details()
|
|
1041
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
1042
|
+
|
|
1043
|
+
async def save_billing_details(self, **billing_fields: Any) -> Optional[Dict[str, Any]]:
|
|
1044
|
+
"""Async version of AssistantRuntimeClient.save_billing_details."""
|
|
1045
|
+
endpoint, payload = self._prepare_save_billing_details(billing_fields)
|
|
1046
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1047
|
+
|
|
1048
|
+
# =========================================================================
|
|
1049
|
+
# Prepaid Credit APIs
|
|
1050
|
+
# =========================================================================
|
|
1051
|
+
|
|
1052
|
+
async def get_credit_balance(self) -> Optional[Dict[str, Any]]:
|
|
1053
|
+
"""Async version of AssistantRuntimeClient.get_credit_balance."""
|
|
1054
|
+
endpoint, params = self._prepare_get_credit_balance()
|
|
1055
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
1056
|
+
|
|
1057
|
+
async def purchase_credits(
|
|
1058
|
+
self, credit_amount: int, gateway: str = None
|
|
1059
|
+
) -> Optional[Dict[str, Any]]:
|
|
1060
|
+
"""Async version of AssistantRuntimeClient.purchase_credits."""
|
|
1061
|
+
endpoint, payload = self._prepare_purchase_credits(credit_amount, gateway)
|
|
1062
|
+
return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
|
|
1063
|
+
|
|
1064
|
+
async def get_expiring_credits(self) -> Optional[Dict[str, Any]]:
|
|
1065
|
+
"""Async version of AssistantRuntimeClient.get_expiring_credits."""
|
|
1066
|
+
endpoint, params = self._prepare_get_expiring_credits()
|
|
1067
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
1068
|
+
|
|
1069
|
+
async def get_consumption_breakdown(self, days: int = 30) -> Optional[Dict[str, Any]]:
|
|
1070
|
+
"""Async version of AssistantRuntimeClient.get_consumption_breakdown."""
|
|
1071
|
+
endpoint, params = self._prepare_get_consumption_breakdown(days)
|
|
1072
|
+
return await self._request_get(endpoint, params, api_base=self.billing_api_base)
|
|
1073
|
+
|
|
1074
|
+
# =========================================================================
|
|
1075
|
+
# Conversation APIs
|
|
1076
|
+
# =========================================================================
|
|
1077
|
+
|
|
1078
|
+
async def list_conversations(
|
|
1079
|
+
self,
|
|
1080
|
+
user_id: Optional[str] = None,
|
|
1081
|
+
limit: int = 50,
|
|
1082
|
+
offset: int = 0,
|
|
1083
|
+
include_deleted: bool = False,
|
|
1084
|
+
from_date: Optional[str] = None,
|
|
1085
|
+
to_date: Optional[str] = None,
|
|
1086
|
+
) -> Optional[Dict[str, Any]]:
|
|
1087
|
+
"""Async version of AssistantRuntimeClient.list_conversations."""
|
|
1088
|
+
endpoint, params = self._prepare_list_conversations(user_id, limit, offset, include_deleted, from_date, to_date)
|
|
1089
|
+
return await self._request_get(endpoint, params)
|
|
1090
|
+
|
|
1091
|
+
async def get_conversation(self, conversation_id: str) -> Optional[Dict[str, Any]]:
|
|
1092
|
+
"""Async version of AssistantRuntimeClient.get_conversation."""
|
|
1093
|
+
endpoint, params = self._prepare_get_conversation(conversation_id)
|
|
1094
|
+
return await self._request_get(endpoint, params)
|
|
1095
|
+
|
|
1096
|
+
async def get_messages(
|
|
1097
|
+
self,
|
|
1098
|
+
conversation_id: str,
|
|
1099
|
+
limit: int = 100,
|
|
1100
|
+
offset: int = 0,
|
|
1101
|
+
include_deleted: bool = False,
|
|
1102
|
+
) -> Optional[Dict[str, Any]]:
|
|
1103
|
+
"""Async version of AssistantRuntimeClient.get_messages."""
|
|
1104
|
+
endpoint, params = self._prepare_get_messages(conversation_id, limit, offset, include_deleted)
|
|
1105
|
+
return await self._request_get(endpoint, params)
|
|
1106
|
+
|
|
1107
|
+
async def create_message(
|
|
1108
|
+
self,
|
|
1109
|
+
conversation_id: str,
|
|
1110
|
+
message_id: str,
|
|
1111
|
+
role: str,
|
|
1112
|
+
content: str,
|
|
1113
|
+
user_id: Optional[str] = None,
|
|
1114
|
+
tokens_used: int = 0,
|
|
1115
|
+
context: Optional[Dict[str, Any]] = None,
|
|
1116
|
+
) -> Optional[Dict[str, Any]]:
|
|
1117
|
+
"""Async version of AssistantRuntimeClient.create_message."""
|
|
1118
|
+
endpoint, payload = self._prepare_create_message(conversation_id, message_id, role, content, user_id, tokens_used, context)
|
|
1119
|
+
return await self._request_post_json(endpoint, payload)
|
|
1120
|
+
|
|
1121
|
+
async def update_conversation(
|
|
1122
|
+
self,
|
|
1123
|
+
conversation_id: str,
|
|
1124
|
+
title: Optional[str] = None,
|
|
1125
|
+
user_id: Optional[str] = None,
|
|
1126
|
+
) -> Optional[Dict[str, Any]]:
|
|
1127
|
+
"""Async version of AssistantRuntimeClient.update_conversation."""
|
|
1128
|
+
endpoint, payload = self._prepare_update_conversation(conversation_id, title, user_id)
|
|
1129
|
+
return await self._request_post_json(endpoint, payload)
|
|
1130
|
+
|
|
1131
|
+
async def delete_conversation(self, conversation_id: str, hard_delete: bool = False) -> Optional[Dict[str, Any]]:
|
|
1132
|
+
"""Delete a conversation. Use hard_delete=True for permanent GDPR erasure."""
|
|
1133
|
+
endpoint, payload = self._prepare_delete_conversation(conversation_id, hard_delete)
|
|
1134
|
+
return await self._request_post_json(endpoint, payload)
|
|
1135
|
+
|
|
1136
|
+
async def delete_message(self, conversation_id: str, message_id: str) -> Optional[Dict[str, Any]]:
|
|
1137
|
+
"""Async version of AssistantRuntimeClient.delete_message."""
|
|
1138
|
+
endpoint, payload = self._prepare_delete_message(conversation_id, message_id)
|
|
1139
|
+
return await self._request_post_json(endpoint, payload)
|
|
1140
|
+
|
|
1141
|
+
async def get_sync_stats(self) -> Optional[Dict[str, Any]]:
|
|
1142
|
+
"""Async version of AssistantRuntimeClient.get_sync_stats."""
|
|
1143
|
+
endpoint, params = self._prepare_get_sync_stats()
|
|
1144
|
+
return await self._request_get(endpoint, params)
|
|
1145
|
+
|
|
1146
|
+
# =========================================================================
|
|
1147
|
+
# Streaming Events APIs (Historical)
|
|
1148
|
+
# =========================================================================
|
|
1149
|
+
|
|
1150
|
+
async def get_message_events(
|
|
1151
|
+
self,
|
|
1152
|
+
conversation_id: str,
|
|
1153
|
+
message_id: Optional[str] = None,
|
|
1154
|
+
event_types: Optional[list] = None,
|
|
1155
|
+
limit: int = 100,
|
|
1156
|
+
offset: int = 0,
|
|
1157
|
+
) -> Optional[Dict[str, Any]]:
|
|
1158
|
+
"""Async version of AssistantRuntimeClient.get_message_events."""
|
|
1159
|
+
endpoint, params = self._prepare_get_message_events(conversation_id, message_id, event_types, limit, offset)
|
|
1160
|
+
return await self._request_get(endpoint, params)
|
|
1161
|
+
|
|
1162
|
+
async def get_tool_execution_stats(
|
|
1163
|
+
self,
|
|
1164
|
+
conversation_id: Optional[str] = None,
|
|
1165
|
+
from_date: Optional[str] = None,
|
|
1166
|
+
to_date: Optional[str] = None,
|
|
1167
|
+
) -> Optional[Dict[str, Any]]:
|
|
1168
|
+
"""Async version of AssistantRuntimeClient.get_tool_execution_stats."""
|
|
1169
|
+
endpoint, params = self._prepare_get_tool_execution_stats(conversation_id, from_date, to_date)
|
|
1170
|
+
return await self._request_get(endpoint, params)
|
|
1171
|
+
|
|
1172
|
+
# =========================================================================
|
|
1173
|
+
# User & MCP Server APIs
|
|
1174
|
+
# =========================================================================
|
|
1175
|
+
|
|
1176
|
+
async def register_user(
|
|
1177
|
+
self,
|
|
1178
|
+
user_id: str,
|
|
1179
|
+
display_name: Optional[str] = None,
|
|
1180
|
+
custom_instructions: Optional[str] = None,
|
|
1181
|
+
locale: Optional[str] = None,
|
|
1182
|
+
timezone: Optional[str] = None,
|
|
1183
|
+
user_role: Optional[str] = None,
|
|
1184
|
+
email: Optional[str] = None,
|
|
1185
|
+
registered_by: Optional[str] = None,
|
|
1186
|
+
) -> Dict[str, Any]:
|
|
1187
|
+
"""Async version of AssistantRuntimeClient.register_user."""
|
|
1188
|
+
endpoint, params = self._prepare_register_user(
|
|
1189
|
+
user_id, display_name, custom_instructions,
|
|
1190
|
+
locale=locale, timezone=timezone, user_role=user_role, email=email,
|
|
1191
|
+
registered_by=registered_by,
|
|
1192
|
+
)
|
|
1193
|
+
return await self._request_post_form(endpoint, params)
|
|
1194
|
+
|
|
1195
|
+
async def invite_user(
|
|
1196
|
+
self,
|
|
1197
|
+
user_id: str,
|
|
1198
|
+
user_role: Optional[str] = None,
|
|
1199
|
+
invited_by: Optional[str] = None,
|
|
1200
|
+
) -> Dict[str, Any]:
|
|
1201
|
+
"""Async version of AssistantRuntimeClient.invite_user."""
|
|
1202
|
+
endpoint, params = self._prepare_invite_user(user_id, user_role, invited_by)
|
|
1203
|
+
return await self._request_post_form(endpoint, params)
|
|
1204
|
+
|
|
1205
|
+
async def revoke_invite(
|
|
1206
|
+
self,
|
|
1207
|
+
user_id: str,
|
|
1208
|
+
revoked_by: Optional[str] = None,
|
|
1209
|
+
) -> Dict[str, Any]:
|
|
1210
|
+
"""Async version of AssistantRuntimeClient.revoke_invite."""
|
|
1211
|
+
endpoint, params = self._prepare_revoke_invite(user_id, revoked_by)
|
|
1212
|
+
return await self._request_post_form(endpoint, params)
|
|
1213
|
+
|
|
1214
|
+
async def resend_invite(
|
|
1215
|
+
self,
|
|
1216
|
+
user_id: str,
|
|
1217
|
+
resent_by: Optional[str] = None,
|
|
1218
|
+
) -> Dict[str, Any]:
|
|
1219
|
+
"""Async version of AssistantRuntimeClient.resend_invite."""
|
|
1220
|
+
endpoint, params = self._prepare_resend_invite(user_id, resent_by)
|
|
1221
|
+
return await self._request_post_form(endpoint, params)
|
|
1222
|
+
|
|
1223
|
+
async def list_invites(self) -> Dict[str, Any]:
|
|
1224
|
+
"""Async version of AssistantRuntimeClient.list_invites."""
|
|
1225
|
+
endpoint, params = self._prepare_list_invites()
|
|
1226
|
+
return await self._request_get(endpoint, params)
|
|
1227
|
+
|
|
1228
|
+
async def get_member_audit_log(self, limit: int = 100, offset: int = 0) -> Dict[str, Any]:
|
|
1229
|
+
"""Async version of AssistantRuntimeClient.get_member_audit_log."""
|
|
1230
|
+
endpoint, params = self._prepare_get_member_audit_log(limit, offset)
|
|
1231
|
+
return await self._request_get(endpoint, params)
|
|
1232
|
+
|
|
1233
|
+
async def get_user(self, user_id: str) -> Optional[Dict[str, Any]]:
|
|
1234
|
+
"""Async version of AssistantRuntimeClient.get_user."""
|
|
1235
|
+
endpoint, params = self._prepare_get_user(user_id)
|
|
1236
|
+
return await self._request_get(endpoint, params)
|
|
1237
|
+
|
|
1238
|
+
async def get_user_auth_status(self, user_id: str) -> Dict[str, Any]:
|
|
1239
|
+
"""Async version of AssistantRuntimeClient.get_user_auth_status.
|
|
1240
|
+
|
|
1241
|
+
See sync client docstring for the ``_ar_unreachable`` contract.
|
|
1242
|
+
"""
|
|
1243
|
+
endpoint, params = self._prepare_get_user_auth_status(user_id)
|
|
1244
|
+
try:
|
|
1245
|
+
return await self._request_get(endpoint, params)
|
|
1246
|
+
except Exception as e:
|
|
1247
|
+
return {
|
|
1248
|
+
"_ar_unreachable": True,
|
|
1249
|
+
"error": str(e),
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
async def add_user_mcp_server(
|
|
1253
|
+
self,
|
|
1254
|
+
user_id: str,
|
|
1255
|
+
server_name: str,
|
|
1256
|
+
endpoint_url: str,
|
|
1257
|
+
transport_type: str = "SSE",
|
|
1258
|
+
auth_type: str = "OAuth",
|
|
1259
|
+
oauth_client_id: Optional[str] = None,
|
|
1260
|
+
oauth_client_secret: Optional[str] = None,
|
|
1261
|
+
access_token: Optional[str] = None,
|
|
1262
|
+
refresh_token: Optional[str] = None,
|
|
1263
|
+
token_expires_in: int = 3600,
|
|
1264
|
+
api_key: Optional[str] = None,
|
|
1265
|
+
api_key_header: str = "Authorization",
|
|
1266
|
+
allowed_tools: Optional[list] = None,
|
|
1267
|
+
blocked_tools: Optional[list] = None,
|
|
1268
|
+
) -> Dict[str, Any]:
|
|
1269
|
+
"""Async version of AssistantRuntimeClient.add_user_mcp_server."""
|
|
1270
|
+
endpoint, params = self._prepare_add_user_mcp_server(
|
|
1271
|
+
user_id, server_name, endpoint_url, transport_type, auth_type,
|
|
1272
|
+
oauth_client_id, oauth_client_secret, access_token, refresh_token,
|
|
1273
|
+
token_expires_in, api_key, api_key_header, allowed_tools, blocked_tools,
|
|
1274
|
+
)
|
|
1275
|
+
return await self._request_post_form(endpoint, params)
|
|
1276
|
+
|
|
1277
|
+
async def get_user_mcp_servers(self, user_id: str) -> Dict[str, Any]:
|
|
1278
|
+
"""Async version of AssistantRuntimeClient.get_user_mcp_servers."""
|
|
1279
|
+
endpoint, params = self._prepare_get_user_mcp_servers(user_id)
|
|
1280
|
+
try:
|
|
1281
|
+
return await self._request_get(endpoint, params)
|
|
1282
|
+
except Exception as e:
|
|
1283
|
+
return {"user_id": user_id, "mcp_servers": [], "error": str(e)}
|
|
1284
|
+
|
|
1285
|
+
async def update_mcp_server_tokens(
|
|
1286
|
+
self,
|
|
1287
|
+
user_id: str,
|
|
1288
|
+
server_name: str,
|
|
1289
|
+
access_token: str,
|
|
1290
|
+
refresh_token: Optional[str] = None,
|
|
1291
|
+
token_expires_in: int = 3600,
|
|
1292
|
+
) -> Dict[str, Any]:
|
|
1293
|
+
"""Async version of AssistantRuntimeClient.update_mcp_server_tokens."""
|
|
1294
|
+
endpoint, params = self._prepare_update_mcp_server_tokens(user_id, server_name, access_token, refresh_token, token_expires_in)
|
|
1295
|
+
return await self._request_post_form(endpoint, params)
|
|
1296
|
+
|
|
1297
|
+
async def remove_user_mcp_server(self, user_id: str, server_name: str) -> Dict[str, Any]:
|
|
1298
|
+
"""Async version of AssistantRuntimeClient.remove_user_mcp_server."""
|
|
1299
|
+
endpoint, params = self._prepare_remove_user_mcp_server(user_id, server_name)
|
|
1300
|
+
return await self._request_delete(endpoint, params)
|
|
1301
|
+
|
|
1302
|
+
async def list_users(
|
|
1303
|
+
self,
|
|
1304
|
+
status: Optional[str] = None,
|
|
1305
|
+
limit: int = 50,
|
|
1306
|
+
offset: int = 0,
|
|
1307
|
+
include_mcp_count: bool = True,
|
|
1308
|
+
) -> Dict[str, Any]:
|
|
1309
|
+
"""Async version of AssistantRuntimeClient.list_users."""
|
|
1310
|
+
endpoint, params = self._prepare_list_users(status, limit, offset, include_mcp_count)
|
|
1311
|
+
return await self._request_get(endpoint, params)
|
|
1312
|
+
|
|
1313
|
+
async def update_user(
|
|
1314
|
+
self,
|
|
1315
|
+
user_id: str,
|
|
1316
|
+
display_name: Optional[str] = None,
|
|
1317
|
+
custom_instructions: Optional[str] = None,
|
|
1318
|
+
locale: Optional[str] = None,
|
|
1319
|
+
timezone: Optional[str] = None,
|
|
1320
|
+
user_role: Optional[str] = None,
|
|
1321
|
+
email: Optional[str] = None,
|
|
1322
|
+
job_title: Optional[str] = None,
|
|
1323
|
+
department: Optional[str] = None,
|
|
1324
|
+
about: Optional[str] = None,
|
|
1325
|
+
) -> Dict[str, Any]:
|
|
1326
|
+
"""Async version of AssistantRuntimeClient.update_user."""
|
|
1327
|
+
endpoint, params = self._prepare_update_user(
|
|
1328
|
+
user_id, display_name, custom_instructions,
|
|
1329
|
+
locale=locale, timezone=timezone, user_role=user_role, email=email,
|
|
1330
|
+
job_title=job_title, department=department, about=about,
|
|
1331
|
+
)
|
|
1332
|
+
return await self._request_post_form(endpoint, params)
|
|
1333
|
+
|
|
1334
|
+
async def deregister_user(self, user_id: str) -> Dict[str, Any]:
|
|
1335
|
+
"""Async version of AssistantRuntimeClient.deregister_user."""
|
|
1336
|
+
endpoint, params = self._prepare_deregister_user(user_id)
|
|
1337
|
+
return await self._request_post_form(endpoint, params)
|
|
1338
|
+
|
|
1339
|
+
async def get_user_limit_status(self) -> Dict[str, Any]:
|
|
1340
|
+
"""Async version of AssistantRuntimeClient.get_user_limit_status."""
|
|
1341
|
+
endpoint, params = self._prepare_get_user_limit_status()
|
|
1342
|
+
return await self._request_get(endpoint, params)
|
|
1343
|
+
|
|
1344
|
+
async def suspend_user(self, user_id: str) -> Dict[str, Any]:
|
|
1345
|
+
"""Async version of AssistantRuntimeClient.suspend_user."""
|
|
1346
|
+
endpoint, params = self._prepare_suspend_user(user_id)
|
|
1347
|
+
return await self._request_post_form(endpoint, params)
|
|
1348
|
+
|
|
1349
|
+
async def revoke_user(self, user_id: str) -> Dict[str, Any]:
|
|
1350
|
+
"""Async version of AssistantRuntimeClient.revoke_user."""
|
|
1351
|
+
endpoint, params = self._prepare_revoke_user(user_id)
|
|
1352
|
+
return await self._request_post_form(endpoint, params)
|
|
1353
|
+
|
|
1354
|
+
async def set_user_credit_limit(
|
|
1355
|
+
self,
|
|
1356
|
+
user_id: str,
|
|
1357
|
+
monthly_credit_limit: float = 0,
|
|
1358
|
+
acted_by: Optional[str] = None,
|
|
1359
|
+
) -> Dict[str, Any]:
|
|
1360
|
+
"""Async version: Set per-user monthly credit limit."""
|
|
1361
|
+
endpoint = "users.set_user_credit_limit"
|
|
1362
|
+
params = {
|
|
1363
|
+
"tenant_id": self.tenant_id,
|
|
1364
|
+
"user_id": user_id,
|
|
1365
|
+
"monthly_credit_limit": str(monthly_credit_limit),
|
|
1366
|
+
}
|
|
1367
|
+
if acted_by:
|
|
1368
|
+
params["acted_by"] = acted_by
|
|
1369
|
+
return await self._request_post_form(endpoint, params)
|
|
1370
|
+
|
|
1371
|
+
async def get_my_credit_status(self, user_id: str) -> Dict[str, Any]:
|
|
1372
|
+
"""Async version: Get credit usage status for a specific user."""
|
|
1373
|
+
endpoint = "users.get_my_credit_status"
|
|
1374
|
+
params = {
|
|
1375
|
+
"tenant_id": self.tenant_id,
|
|
1376
|
+
"user_id": user_id,
|
|
1377
|
+
}
|
|
1378
|
+
return await self._request_get(endpoint, params)
|
|
1379
|
+
|
|
1380
|
+
# =========================================================================
|
|
1381
|
+
# Workflow APIs
|
|
1382
|
+
# =========================================================================
|
|
1383
|
+
|
|
1384
|
+
async def create_workflow(
|
|
1385
|
+
self,
|
|
1386
|
+
workflow_name: str,
|
|
1387
|
+
graph_json: Optional[str] = None,
|
|
1388
|
+
description: str = "",
|
|
1389
|
+
default_model_id: Optional[str] = None,
|
|
1390
|
+
default_user_id: Optional[str] = None,
|
|
1391
|
+
error_strategy: str = "fail_fast",
|
|
1392
|
+
timeout_seconds: int = 600,
|
|
1393
|
+
) -> Optional[Dict[str, Any]]:
|
|
1394
|
+
"""Async version of AssistantRuntimeClient.create_workflow."""
|
|
1395
|
+
endpoint, payload = self._prepare_create_workflow(
|
|
1396
|
+
workflow_name, graph_json, description, default_model_id,
|
|
1397
|
+
default_user_id, error_strategy, timeout_seconds,
|
|
1398
|
+
)
|
|
1399
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1400
|
+
|
|
1401
|
+
async def get_workflow(
|
|
1402
|
+
self,
|
|
1403
|
+
name: Optional[str] = None,
|
|
1404
|
+
workflow_name: Optional[str] = None,
|
|
1405
|
+
) -> Optional[Dict[str, Any]]:
|
|
1406
|
+
"""Async version of AssistantRuntimeClient.get_workflow."""
|
|
1407
|
+
endpoint, params = self._prepare_get_workflow(name, workflow_name)
|
|
1408
|
+
return await self._request_get(endpoint, params, api_base=self.workflows_api_base)
|
|
1409
|
+
|
|
1410
|
+
async def update_workflow(
|
|
1411
|
+
self,
|
|
1412
|
+
name: str,
|
|
1413
|
+
graph_json: Optional[str] = None,
|
|
1414
|
+
workflow_name: Optional[str] = None,
|
|
1415
|
+
description: Optional[str] = None,
|
|
1416
|
+
status: Optional[str] = None,
|
|
1417
|
+
default_model_id: Optional[str] = None,
|
|
1418
|
+
default_user_id: Optional[str] = None,
|
|
1419
|
+
error_strategy: Optional[str] = None,
|
|
1420
|
+
timeout_seconds: Optional[int] = None,
|
|
1421
|
+
max_node_executions: Optional[int] = None,
|
|
1422
|
+
max_retries: Optional[int] = None,
|
|
1423
|
+
) -> Optional[Dict[str, Any]]:
|
|
1424
|
+
"""Async version of AssistantRuntimeClient.update_workflow."""
|
|
1425
|
+
endpoint, payload = self._prepare_update_workflow(
|
|
1426
|
+
name, graph_json, workflow_name, description, status,
|
|
1427
|
+
default_model_id, default_user_id, error_strategy,
|
|
1428
|
+
timeout_seconds, max_node_executions, max_retries,
|
|
1429
|
+
)
|
|
1430
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1431
|
+
|
|
1432
|
+
async def delete_workflow(self, name: str) -> Optional[Dict[str, Any]]:
|
|
1433
|
+
"""Async version of AssistantRuntimeClient.delete_workflow."""
|
|
1434
|
+
endpoint, payload = self._prepare_delete_workflow(name)
|
|
1435
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1436
|
+
|
|
1437
|
+
async def list_workflows(
|
|
1438
|
+
self,
|
|
1439
|
+
status: Optional[str] = None,
|
|
1440
|
+
page: int = 0,
|
|
1441
|
+
page_size: int = 20,
|
|
1442
|
+
) -> Optional[Dict[str, Any]]:
|
|
1443
|
+
"""Async version of AssistantRuntimeClient.list_workflows."""
|
|
1444
|
+
endpoint, params = self._prepare_list_workflows(status, page, page_size)
|
|
1445
|
+
return await self._request_get(endpoint, params, api_base=self.workflows_api_base)
|
|
1446
|
+
|
|
1447
|
+
async def execute_workflow(
|
|
1448
|
+
self,
|
|
1449
|
+
name: str,
|
|
1450
|
+
input_data: Optional[str] = None,
|
|
1451
|
+
user_id: Optional[str] = None,
|
|
1452
|
+
) -> Optional[Dict[str, Any]]:
|
|
1453
|
+
"""Async version of AssistantRuntimeClient.execute_workflow."""
|
|
1454
|
+
endpoint, payload = self._prepare_execute_workflow(name, input_data, user_id)
|
|
1455
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1456
|
+
|
|
1457
|
+
async def execute_workflow_from_event(
|
|
1458
|
+
self,
|
|
1459
|
+
workflow_name: str,
|
|
1460
|
+
input_data: Dict[str, Any],
|
|
1461
|
+
user_id: str,
|
|
1462
|
+
trigger_id: str,
|
|
1463
|
+
) -> Optional[Dict[str, Any]]:
|
|
1464
|
+
"""Async version of AssistantRuntimeClient.execute_workflow_from_event."""
|
|
1465
|
+
endpoint, payload = self._prepare_execute_workflow_from_event(
|
|
1466
|
+
workflow_name, input_data, user_id, trigger_id,
|
|
1467
|
+
)
|
|
1468
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1469
|
+
|
|
1470
|
+
async def cancel_workflow_run(self, run_name: str) -> Optional[Dict[str, Any]]:
|
|
1471
|
+
"""Async version of AssistantRuntimeClient.cancel_workflow_run."""
|
|
1472
|
+
endpoint, payload = self._prepare_cancel_workflow_run(run_name)
|
|
1473
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1474
|
+
|
|
1475
|
+
async def get_workflow_run(self, run_name: str) -> Optional[Dict[str, Any]]:
|
|
1476
|
+
"""Async version of AssistantRuntimeClient.get_workflow_run."""
|
|
1477
|
+
endpoint, params = self._prepare_get_workflow_run(run_name)
|
|
1478
|
+
return await self._request_get(endpoint, params, api_base=self.workflows_api_base)
|
|
1479
|
+
|
|
1480
|
+
async def list_workflow_runs(
|
|
1481
|
+
self,
|
|
1482
|
+
workflow_name: Optional[str] = None,
|
|
1483
|
+
status: Optional[str] = None,
|
|
1484
|
+
page: int = 0,
|
|
1485
|
+
page_size: int = 20,
|
|
1486
|
+
) -> Optional[Dict[str, Any]]:
|
|
1487
|
+
"""Async version of AssistantRuntimeClient.list_workflow_runs."""
|
|
1488
|
+
endpoint, params = self._prepare_list_workflow_runs(workflow_name, status, page, page_size)
|
|
1489
|
+
return await self._request_get(endpoint, params, api_base=self.workflows_api_base)
|
|
1490
|
+
|
|
1491
|
+
async def get_workflow_audit_summary(
|
|
1492
|
+
self,
|
|
1493
|
+
workflow_id: str,
|
|
1494
|
+
window: str = "last_7_days",
|
|
1495
|
+
) -> Optional[Dict[str, Any]]:
|
|
1496
|
+
"""Async version of AssistantRuntimeClient.get_workflow_audit_summary."""
|
|
1497
|
+
endpoint, params = self._prepare_get_workflow_audit_summary(workflow_id, window)
|
|
1498
|
+
return await self._request_get(endpoint, params, api_base=self.workflows_api_base)
|
|
1499
|
+
|
|
1500
|
+
async def set_workflow_schedule(
|
|
1501
|
+
self,
|
|
1502
|
+
name: str,
|
|
1503
|
+
cron_expression: str,
|
|
1504
|
+
timezone: str = "UTC",
|
|
1505
|
+
enabled: bool = True,
|
|
1506
|
+
default_input: Optional[str] = None,
|
|
1507
|
+
) -> Optional[Dict[str, Any]]:
|
|
1508
|
+
"""Async version of AssistantRuntimeClient.set_workflow_schedule."""
|
|
1509
|
+
endpoint, payload = self._prepare_set_workflow_schedule(name, cron_expression, timezone, enabled, default_input)
|
|
1510
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1511
|
+
|
|
1512
|
+
async def validate_workflow_graph(self, graph_json: str) -> Optional[Dict[str, Any]]:
|
|
1513
|
+
"""Async version of AssistantRuntimeClient.validate_workflow_graph."""
|
|
1514
|
+
endpoint, payload = self._prepare_validate_workflow_graph(graph_json)
|
|
1515
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1516
|
+
|
|
1517
|
+
async def test_workflow_node(
|
|
1518
|
+
self,
|
|
1519
|
+
node_json: str,
|
|
1520
|
+
input_text: str = "Test input",
|
|
1521
|
+
default_model_id: Optional[str] = None,
|
|
1522
|
+
default_user_id: Optional[str] = None,
|
|
1523
|
+
) -> Optional[Dict[str, Any]]:
|
|
1524
|
+
"""Async version of AssistantRuntimeClient.test_workflow_node."""
|
|
1525
|
+
endpoint, payload = self._prepare_test_workflow_node(node_json, input_text, default_model_id, default_user_id)
|
|
1526
|
+
return await self._request_post_json(endpoint, payload, timeout=120.0, api_base=self.workflows_api_base)
|
|
1527
|
+
|
|
1528
|
+
async def resolve_workflow_tools(
|
|
1529
|
+
self,
|
|
1530
|
+
user_id: str,
|
|
1531
|
+
tool_directives: List[Dict[str, Any]],
|
|
1532
|
+
) -> Optional[Dict[str, Any]]:
|
|
1533
|
+
"""Async version of AssistantRuntimeClient.resolve_workflow_tools."""
|
|
1534
|
+
endpoint, payload = self._prepare_resolve_workflow_tools(user_id, tool_directives)
|
|
1535
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1536
|
+
|
|
1537
|
+
async def run_workflow_node(
|
|
1538
|
+
self,
|
|
1539
|
+
name: str,
|
|
1540
|
+
node_id: str,
|
|
1541
|
+
input_text: str = "Test input",
|
|
1542
|
+
user_id: Optional[str] = None,
|
|
1543
|
+
) -> Optional[Dict[str, Any]]:
|
|
1544
|
+
"""Async version of AssistantRuntimeClient.run_workflow_node."""
|
|
1545
|
+
endpoint, payload = self._prepare_run_workflow_node(name, node_id, input_text, user_id)
|
|
1546
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base, timeout=120.0)
|
|
1547
|
+
|
|
1548
|
+
# --- Workflow Templates ---
|
|
1549
|
+
|
|
1550
|
+
async def export_workflow(
|
|
1551
|
+
self,
|
|
1552
|
+
name: str,
|
|
1553
|
+
template_name: Optional[str] = None,
|
|
1554
|
+
category: str = "General",
|
|
1555
|
+
save_as_template: bool = False,
|
|
1556
|
+
is_public: bool = False,
|
|
1557
|
+
) -> Optional[Dict[str, Any]]:
|
|
1558
|
+
"""Async version of AssistantRuntimeClient.export_workflow."""
|
|
1559
|
+
endpoint, payload = self._prepare_export_workflow(name, template_name, category, save_as_template, is_public)
|
|
1560
|
+
return await self._request_post_json(endpoint, payload, api_base=self.workflows_api_base)
|
|
1561
|
+
|
|
1562
|
+
# `list_templates`, `get_template`, `import_template`, `update_template`,
|
|
1563
|
+
# and `delete_template` removed in chunk 4 — use the async marketplace
|
|
1564
|
+
# methods (`list_listings(listing_type="Workflow")`, `get_listing`,
|
|
1565
|
+
# `import_listing`, `update_listing`, `delete_listing`) instead.
|
|
1566
|
+
|
|
1567
|
+
async def upload_listing_from_json(
|
|
1568
|
+
self,
|
|
1569
|
+
file_path: str,
|
|
1570
|
+
user_id: str,
|
|
1571
|
+
is_public: bool = False,
|
|
1572
|
+
is_published: bool = True,
|
|
1573
|
+
plan_tier: Optional[str] = None,
|
|
1574
|
+
timeout: Optional[float] = None,
|
|
1575
|
+
) -> Optional[Dict[str, Any]]:
|
|
1576
|
+
"""Async upload an ``ar_workflow_template_v1`` JSON file + create a listing."""
|
|
1577
|
+
payload: Dict[str, Any] = {
|
|
1578
|
+
"tenant_id": self.tenant_id,
|
|
1579
|
+
"user_id": user_id,
|
|
1580
|
+
"is_public": "1" if is_public else "0",
|
|
1581
|
+
"is_published": "1" if is_published else "0",
|
|
1582
|
+
}
|
|
1583
|
+
if plan_tier:
|
|
1584
|
+
payload["plan_tier"] = plan_tier
|
|
1585
|
+
url = f"{self.marketplace_api_base}.publishing.upload_listing_from_json"
|
|
1586
|
+
payload = self._with_site_url(payload)
|
|
1587
|
+
headers = self._get_headers(payload, for_query_string=False)
|
|
1588
|
+
timeout_val = timeout or self.timeout
|
|
1589
|
+
|
|
1590
|
+
data = aiohttp.FormData()
|
|
1591
|
+
for k, v in payload.items():
|
|
1592
|
+
data.add_field(k, str(v))
|
|
1593
|
+
with open(file_path, "rb") as f:
|
|
1594
|
+
data.add_field(
|
|
1595
|
+
"file", f.read(),
|
|
1596
|
+
filename=os.path.basename(file_path),
|
|
1597
|
+
content_type="application/json",
|
|
1598
|
+
)
|
|
1599
|
+
|
|
1600
|
+
async with self.session.post(
|
|
1601
|
+
url, data=data, headers=headers,
|
|
1602
|
+
timeout=aiohttp.ClientTimeout(total=timeout_val),
|
|
1603
|
+
) as resp:
|
|
1604
|
+
resp.raise_for_status()
|
|
1605
|
+
result = await resp.json()
|
|
1606
|
+
return result.get("message", result)
|
|
1607
|
+
|
|
1608
|
+
# `rate_template` removed in chunk 4 — use `rate_listing` instead.
|
|
1609
|
+
# `download_template` removed in chunk 5 — use `download_listing_as_json` instead.
|
|
1610
|
+
|
|
1611
|
+
# --- GDPR / Privacy ---
|
|
1612
|
+
|
|
1613
|
+
async def export_user_data(self, user_id: str) -> Optional[Dict[str, Any]]:
|
|
1614
|
+
"""Export all user data as structured JSON (GDPR Article 20)."""
|
|
1615
|
+
endpoint, payload = self._prepare_export_user_data(user_id)
|
|
1616
|
+
return await self._request_post_json(endpoint, payload)
|
|
1617
|
+
|
|
1618
|
+
async def erase_user_data(self, user_id: str) -> Optional[Dict[str, Any]]:
|
|
1619
|
+
"""Permanently delete all user data (GDPR Article 17)."""
|
|
1620
|
+
endpoint, payload = self._prepare_erase_user_data(user_id)
|
|
1621
|
+
return await self._request_post_json(endpoint, payload)
|
|
1622
|
+
|
|
1623
|
+
async def rectify_user_data(self, user_id: str, updates: dict) -> Optional[Dict[str, Any]]:
|
|
1624
|
+
"""Update user's personal data (GDPR Article 16)."""
|
|
1625
|
+
endpoint, payload = self._prepare_rectify_user_data(user_id, updates)
|
|
1626
|
+
return await self._request_post_json(endpoint, payload)
|
|
1627
|
+
|
|
1628
|
+
async def restrict_user_processing(self, user_id: str, restrict: bool = True) -> Optional[Dict[str, Any]]:
|
|
1629
|
+
"""Restrict or unrestrict data processing for a user (GDPR Article 18)."""
|
|
1630
|
+
endpoint, payload = self._prepare_restrict_user_processing(user_id, restrict)
|
|
1631
|
+
return await self._request_post_json(endpoint, payload)
|
|
1632
|
+
|
|
1633
|
+
async def update_user_consent(self, user_id: str, consent_type: str, granted: bool = True) -> Optional[Dict[str, Any]]:
|
|
1634
|
+
"""Update user consent for a specific processing activity."""
|
|
1635
|
+
endpoint, payload = self._prepare_update_user_consent(user_id, consent_type, granted)
|
|
1636
|
+
return await self._request_post_json(endpoint, payload)
|
|
1637
|
+
|
|
1638
|
+
async def create_ticket(self, user_id: str, subject: str, description: str,
|
|
1639
|
+
category: Optional[str] = None,
|
|
1640
|
+
conversation_id: Optional[str] = None,
|
|
1641
|
+
environment: Optional[dict] = None,
|
|
1642
|
+
attachment_ids: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
|
|
1643
|
+
"""Raise a support ticket. Returns {ticket_id, portal_link}."""
|
|
1644
|
+
endpoint, payload = self._prepare_create_ticket(
|
|
1645
|
+
user_id, subject, description, category, conversation_id, environment,
|
|
1646
|
+
attachment_ids)
|
|
1647
|
+
return await self._request_post_json(endpoint, payload)
|
|
1648
|
+
|
|
1649
|
+
async def submit_feedback(self, user_id: str, rating: Optional[int] = None,
|
|
1650
|
+
comment: Optional[str] = None,
|
|
1651
|
+
category: Optional[str] = None,
|
|
1652
|
+
conversation_id: Optional[str] = None,
|
|
1653
|
+
environment: Optional[dict] = None) -> Optional[Dict[str, Any]]:
|
|
1654
|
+
"""Submit product/service feedback. Returns {feedback_id}."""
|
|
1655
|
+
endpoint, payload = self._prepare_submit_feedback(
|
|
1656
|
+
user_id, rating, comment, category, conversation_id, environment)
|
|
1657
|
+
return await self._request_post_json(endpoint, payload)
|
|
1658
|
+
|
|
1659
|
+
async def list_tickets(self, user_id: str, status: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
1660
|
+
"""List the user's support tickets. Returns {tickets: [...]}."""
|
|
1661
|
+
endpoint, payload = self._prepare_list_tickets(user_id, status)
|
|
1662
|
+
return await self._request_post_json(endpoint, payload)
|
|
1663
|
+
|
|
1664
|
+
async def get_ticket_thread(self, user_id: str, ticket_id: str) -> Optional[Dict[str, Any]]:
|
|
1665
|
+
"""Get a ticket's full conversation thread. Returns {ticket, messages: [...]}."""
|
|
1666
|
+
endpoint, payload = self._prepare_get_ticket_thread(user_id, ticket_id)
|
|
1667
|
+
return await self._request_post_json(endpoint, payload)
|
|
1668
|
+
|
|
1669
|
+
async def reply_to_ticket(self, user_id: str, ticket_id: str, message: str,
|
|
1670
|
+
attachment_ids: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
|
|
1671
|
+
"""Post a reply to a ticket. Returns {message_id}."""
|
|
1672
|
+
endpoint, payload = self._prepare_reply_to_ticket(user_id, ticket_id, message, attachment_ids)
|
|
1673
|
+
return await self._request_post_json(endpoint, payload)
|
|
1674
|
+
|
|
1675
|
+
async def upload_ticket_attachment(
|
|
1676
|
+
self,
|
|
1677
|
+
user_id: str,
|
|
1678
|
+
file_name: str,
|
|
1679
|
+
file_data: bytes,
|
|
1680
|
+
content_type: Optional[str] = None,
|
|
1681
|
+
) -> Optional[Dict[str, Any]]:
|
|
1682
|
+
"""Async version of AssistantRuntimeClient.upload_ticket_attachment."""
|
|
1683
|
+
endpoint, params, f_field, f_name, f_data, c_type = self._prepare_upload_ticket_attachment(
|
|
1684
|
+
user_id, file_name, file_data, content_type,
|
|
1685
|
+
)
|
|
1686
|
+
return await self._request_post_multipart(
|
|
1687
|
+
endpoint, params=params, file_field=f_field,
|
|
1688
|
+
file_name=f_name, file_data=f_data, content_type=c_type,
|
|
1689
|
+
timeout=120.0,
|
|
1690
|
+
)
|
|
1691
|
+
|
|
1692
|
+
async def get_tenant_privacy_config(self) -> Optional[Dict[str, Any]]:
|
|
1693
|
+
"""Get tenant's privacy policy configuration."""
|
|
1694
|
+
endpoint, payload = self._prepare_get_tenant_privacy_config()
|
|
1695
|
+
return await self._request_post_json(endpoint, payload)
|
|
1696
|
+
|
|
1697
|
+
async def update_tenant_privacy_config(self, config: dict) -> Optional[Dict[str, Any]]:
|
|
1698
|
+
"""Update tenant's privacy policy configuration."""
|
|
1699
|
+
endpoint, payload = self._prepare_update_tenant_privacy_config(config)
|
|
1700
|
+
return await self._request_post_json(endpoint, payload)
|
|
1701
|
+
|
|
1702
|
+
# --- Heartbeat & Notifications ---
|
|
1703
|
+
|
|
1704
|
+
async def heartbeat(
|
|
1705
|
+
self,
|
|
1706
|
+
faco_version: Optional[str] = None,
|
|
1707
|
+
fac_version: Optional[str] = None,
|
|
1708
|
+
frappe_version: Optional[str] = None,
|
|
1709
|
+
erpnext_version: Optional[str] = None,
|
|
1710
|
+
python_version: Optional[str] = None,
|
|
1711
|
+
copilot_version: Optional[str] = None,
|
|
1712
|
+
timeout: Optional[float] = None,
|
|
1713
|
+
) -> Optional[Dict[str, Any]]:
|
|
1714
|
+
"""Async send version/health info and receive pending notifications."""
|
|
1715
|
+
endpoint, payload = self._prepare_heartbeat(
|
|
1716
|
+
faco_version, fac_version, frappe_version, erpnext_version,
|
|
1717
|
+
python_version, copilot_version,
|
|
1718
|
+
)
|
|
1719
|
+
return await self._request_post_json(endpoint, payload, timeout=timeout)
|
|
1720
|
+
|
|
1721
|
+
async def get_notifications(self, user_id: str, timeout: Optional[float] = None) -> Optional[Dict[str, Any]]:
|
|
1722
|
+
"""Async fetch pending notifications for a user."""
|
|
1723
|
+
endpoint, payload = self._prepare_get_notifications(user_id)
|
|
1724
|
+
return await self._request_post_json(endpoint, payload, timeout=timeout)
|
|
1725
|
+
|
|
1726
|
+
async def dismiss_notification(
|
|
1727
|
+
self,
|
|
1728
|
+
notification_id: str,
|
|
1729
|
+
user_id: str,
|
|
1730
|
+
timeout: Optional[float] = None,
|
|
1731
|
+
) -> Optional[Dict[str, Any]]:
|
|
1732
|
+
"""Async record that a user has dismissed a notification."""
|
|
1733
|
+
endpoint, payload = self._prepare_dismiss_notification(notification_id, user_id)
|
|
1734
|
+
return await self._request_post_json(endpoint, payload, timeout=timeout)
|
|
1735
|
+
|
|
1736
|
+
# -------------------------------------------------------------------
|
|
1737
|
+
# Marketplace API — async, routes via marketplace_api_base
|
|
1738
|
+
# -------------------------------------------------------------------
|
|
1739
|
+
|
|
1740
|
+
async def list_listings(
|
|
1741
|
+
self,
|
|
1742
|
+
listing_type: Optional[str] = None,
|
|
1743
|
+
category: Optional[str] = None,
|
|
1744
|
+
search: Optional[str] = None,
|
|
1745
|
+
featured_only: bool = False,
|
|
1746
|
+
min_rating: Optional[float] = None,
|
|
1747
|
+
plan_tier: Optional[str] = None,
|
|
1748
|
+
sort_by: Optional[str] = None,
|
|
1749
|
+
page: int = 0,
|
|
1750
|
+
page_size: int = 20,
|
|
1751
|
+
user_id: Optional[str] = None,
|
|
1752
|
+
timeout: Optional[float] = None,
|
|
1753
|
+
) -> Optional[Dict[str, Any]]:
|
|
1754
|
+
endpoint, params = self._prepare_list_listings(
|
|
1755
|
+
listing_type, category, search, featured_only, min_rating,
|
|
1756
|
+
plan_tier, sort_by, page, page_size, user_id,
|
|
1757
|
+
)
|
|
1758
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base, timeout=timeout)
|
|
1759
|
+
|
|
1760
|
+
async def get_listing(
|
|
1761
|
+
self, name: str, user_id: Optional[str] = None,
|
|
1762
|
+
include_source: bool = True,
|
|
1763
|
+
) -> Optional[Dict[str, Any]]:
|
|
1764
|
+
endpoint, params = self._prepare_get_listing(name, user_id, include_source)
|
|
1765
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1766
|
+
|
|
1767
|
+
async def import_listing(
|
|
1768
|
+
self,
|
|
1769
|
+
user_id: str,
|
|
1770
|
+
name: str,
|
|
1771
|
+
new_title: Optional[str] = None,
|
|
1772
|
+
variables: Optional[str] = None,
|
|
1773
|
+
default_model_id: Optional[str] = None,
|
|
1774
|
+
) -> Optional[Dict[str, Any]]:
|
|
1775
|
+
endpoint, payload = self._prepare_import_listing(
|
|
1776
|
+
user_id, name, new_title, variables, default_model_id,
|
|
1777
|
+
)
|
|
1778
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1779
|
+
|
|
1780
|
+
async def update_listing(
|
|
1781
|
+
self,
|
|
1782
|
+
name: str,
|
|
1783
|
+
title: Optional[str] = None,
|
|
1784
|
+
short_description: Optional[str] = None,
|
|
1785
|
+
description: Optional[str] = None,
|
|
1786
|
+
category: Optional[str] = None,
|
|
1787
|
+
tags: Optional[str] = None,
|
|
1788
|
+
icon: Optional[str] = None,
|
|
1789
|
+
is_public: Optional[bool] = None,
|
|
1790
|
+
is_published: Optional[bool] = None,
|
|
1791
|
+
plan_tier: Optional[str] = None,
|
|
1792
|
+
) -> Optional[Dict[str, Any]]:
|
|
1793
|
+
endpoint, payload = self._prepare_update_listing(
|
|
1794
|
+
name, title, short_description, description, category, tags,
|
|
1795
|
+
icon, is_public, is_published, plan_tier,
|
|
1796
|
+
)
|
|
1797
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1798
|
+
|
|
1799
|
+
async def delete_listing(self, name: str) -> Optional[Dict[str, Any]]:
|
|
1800
|
+
endpoint, payload = self._prepare_delete_listing(name)
|
|
1801
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1802
|
+
|
|
1803
|
+
async def rate_listing(
|
|
1804
|
+
self, user_id: str, listing: str, rating: int,
|
|
1805
|
+
review: Optional[str] = None,
|
|
1806
|
+
) -> Optional[Dict[str, Any]]:
|
|
1807
|
+
endpoint, payload = self._prepare_rate_listing(user_id, listing, rating, review)
|
|
1808
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1809
|
+
|
|
1810
|
+
async def report_listing(
|
|
1811
|
+
self, user_id: str, listing: str, reason: str,
|
|
1812
|
+
details: Optional[str] = None,
|
|
1813
|
+
) -> Optional[Dict[str, Any]]:
|
|
1814
|
+
endpoint, payload = self._prepare_report_listing(user_id, listing, reason, details)
|
|
1815
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1816
|
+
|
|
1817
|
+
async def list_pending_reviews(
|
|
1818
|
+
self, page: int = 0, page_size: int = 20,
|
|
1819
|
+
) -> Optional[Dict[str, Any]]:
|
|
1820
|
+
endpoint, params = self._prepare_list_pending_reviews(page, page_size)
|
|
1821
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1822
|
+
|
|
1823
|
+
async def approve_listing(
|
|
1824
|
+
self, listing: str, notes: Optional[str] = None,
|
|
1825
|
+
) -> Optional[Dict[str, Any]]:
|
|
1826
|
+
endpoint, payload = self._prepare_approve_listing(listing, notes)
|
|
1827
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1828
|
+
|
|
1829
|
+
async def reject_listing(
|
|
1830
|
+
self, listing: str, notes: Optional[str] = None,
|
|
1831
|
+
) -> Optional[Dict[str, Any]]:
|
|
1832
|
+
endpoint, payload = self._prepare_reject_listing(listing, notes)
|
|
1833
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1834
|
+
|
|
1835
|
+
async def get_creator_stats(
|
|
1836
|
+
self, user_id: Optional[str] = None,
|
|
1837
|
+
) -> Optional[Dict[str, Any]]:
|
|
1838
|
+
endpoint, params = self._prepare_get_creator_stats(user_id)
|
|
1839
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1840
|
+
|
|
1841
|
+
async def list_my_listings(
|
|
1842
|
+
self,
|
|
1843
|
+
user_id: Optional[str] = None,
|
|
1844
|
+
listing_type: Optional[str] = None,
|
|
1845
|
+
page: int = 0,
|
|
1846
|
+
page_size: int = 20,
|
|
1847
|
+
) -> Optional[Dict[str, Any]]:
|
|
1848
|
+
endpoint, params = self._prepare_list_my_listings(user_id, listing_type, page, page_size)
|
|
1849
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1850
|
+
|
|
1851
|
+
# -------------------------------------------------------------------
|
|
1852
|
+
# Marketplace publishing + downloads + version checks (chunk 5)
|
|
1853
|
+
# -------------------------------------------------------------------
|
|
1854
|
+
|
|
1855
|
+
async def publish_workflow(
|
|
1856
|
+
self,
|
|
1857
|
+
user_id: str,
|
|
1858
|
+
workflow_name: str,
|
|
1859
|
+
template_name: Optional[str] = None,
|
|
1860
|
+
category: str = "General",
|
|
1861
|
+
short_description: Optional[str] = None,
|
|
1862
|
+
description: Optional[str] = None,
|
|
1863
|
+
tags: Optional[str] = None,
|
|
1864
|
+
is_public: bool = False,
|
|
1865
|
+
plan_tier: Optional[str] = None,
|
|
1866
|
+
) -> Optional[Dict[str, Any]]:
|
|
1867
|
+
endpoint, payload = self._prepare_publish_workflow(
|
|
1868
|
+
user_id, workflow_name, template_name, category, short_description,
|
|
1869
|
+
description, tags, is_public, plan_tier,
|
|
1870
|
+
)
|
|
1871
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1872
|
+
|
|
1873
|
+
async def download_listing_as_json(self, name: str) -> Optional[Dict[str, Any]]:
|
|
1874
|
+
endpoint, params = self._prepare_download_listing_as_json(name)
|
|
1875
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1876
|
+
|
|
1877
|
+
async def check_workflow_update(self, name: str) -> Optional[Dict[str, Any]]:
|
|
1878
|
+
endpoint, params = self._prepare_check_workflow_update(name)
|
|
1879
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1880
|
+
|
|
1881
|
+
async def check_all_workflow_updates(self) -> Optional[Dict[str, Any]]:
|
|
1882
|
+
endpoint, params = self._prepare_check_all_workflow_updates()
|
|
1883
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1884
|
+
|
|
1885
|
+
# -------------------------------------------------------------------
|
|
1886
|
+
# Tenant Packs API — admin-grade pack management for the calling tenant
|
|
1887
|
+
# -------------------------------------------------------------------
|
|
1888
|
+
|
|
1889
|
+
async def list_packs(self) -> Optional[Dict[str, Any]]:
|
|
1890
|
+
"""Return every active pack with eligibility + enablement annotations."""
|
|
1891
|
+
endpoint, params = self._prepare_list_packs()
|
|
1892
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1893
|
+
|
|
1894
|
+
async def get_pack_contents(self, pack_id: str) -> Optional[Dict[str, Any]]:
|
|
1895
|
+
"""Return the named prompts + skills of a pack the tenant owns."""
|
|
1896
|
+
endpoint, params = self._prepare_get_pack_contents(pack_id)
|
|
1897
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1898
|
+
|
|
1899
|
+
async def set_industry(
|
|
1900
|
+
self,
|
|
1901
|
+
industry: Optional[str],
|
|
1902
|
+
auto_enable: bool = True,
|
|
1903
|
+
) -> Optional[Dict[str, Any]]:
|
|
1904
|
+
"""Set the calling tenant's industry and optionally auto-enable its pack."""
|
|
1905
|
+
endpoint, payload = self._prepare_set_industry(industry, auto_enable)
|
|
1906
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1907
|
+
|
|
1908
|
+
async def set_pack_enabled(
|
|
1909
|
+
self,
|
|
1910
|
+
pack_id: str,
|
|
1911
|
+
enabled: bool,
|
|
1912
|
+
source: str = "User",
|
|
1913
|
+
) -> Optional[Dict[str, Any]]:
|
|
1914
|
+
"""Toggle a pack on or off for the calling tenant."""
|
|
1915
|
+
endpoint, payload = self._prepare_set_pack_enabled(pack_id, enabled, source)
|
|
1916
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1917
|
+
|
|
1918
|
+
async def get_recommended_pack(
|
|
1919
|
+
self, user_id: Optional[str] = None,
|
|
1920
|
+
) -> Optional[Dict[str, Any]]:
|
|
1921
|
+
"""Return at most one pack to surface in the onboarding recommendation toast."""
|
|
1922
|
+
endpoint, params = self._prepare_get_recommended_pack(user_id)
|
|
1923
|
+
return await self._request_get(endpoint, params, api_base=self.marketplace_api_base)
|
|
1924
|
+
|
|
1925
|
+
async def dismiss_pack_recommendation(self, user_id: str) -> Optional[Dict[str, Any]]:
|
|
1926
|
+
"""Mark the recommendation toast as dismissed for the given user."""
|
|
1927
|
+
endpoint, payload = self._prepare_dismiss_pack_recommendation(user_id)
|
|
1928
|
+
return await self._request_post_json(endpoint, payload, api_base=self.marketplace_api_base)
|
|
1929
|
+
|
|
1930
|
+
# =========================================================================
|
|
1931
|
+
# HITL APIs
|
|
1932
|
+
# =========================================================================
|
|
1933
|
+
|
|
1934
|
+
async def get_pending_interrupt(self, session_id: str, user_id: str) -> Optional[Dict[str, Any]]:
|
|
1935
|
+
"""Async version of AssistantRuntimeClient.get_pending_interrupt."""
|
|
1936
|
+
endpoint, params = self._prepare_get_pending_interrupt(session_id, user_id)
|
|
1937
|
+
return await self._request_get(endpoint, params, api_base=self.api_base)
|
|
1938
|
+
|
|
1939
|
+
async def cancel_session(self, session_id: str) -> Optional[Dict[str, Any]]:
|
|
1940
|
+
"""Async version of AssistantRuntimeClient.cancel_session."""
|
|
1941
|
+
endpoint, payload = self._prepare_cancel_session(session_id)
|
|
1942
|
+
return await self._request_post_json(endpoint, payload, api_base=self.api_base)
|
|
1943
|
+
|
|
1944
|
+
# =========================================================================
|
|
1945
|
+
# Voice API
|
|
1946
|
+
# =========================================================================
|
|
1947
|
+
|
|
1948
|
+
async def transcribe_audio(
|
|
1949
|
+
self,
|
|
1950
|
+
audio_bytes: bytes,
|
|
1951
|
+
mime_type: str = "audio/webm",
|
|
1952
|
+
user_id: Optional[str] = None,
|
|
1953
|
+
duration_ms: int = 0,
|
|
1954
|
+
language: Optional[str] = None,
|
|
1955
|
+
) -> Optional[Dict[str, Any]]:
|
|
1956
|
+
"""
|
|
1957
|
+
Async transcribe an audio blob via AR's voice endpoint.
|
|
1958
|
+
|
|
1959
|
+
Args:
|
|
1960
|
+
audio_bytes: Raw audio bytes.
|
|
1961
|
+
mime_type: MIME type (default: audio/webm).
|
|
1962
|
+
user_id: User identifier for per-user billing attribution.
|
|
1963
|
+
duration_ms: Client-reported recording length (advisory only;
|
|
1964
|
+
billing uses the provider's authoritative duration).
|
|
1965
|
+
language: ISO-639-1 hint ("en", "es"…). Strongly recommended —
|
|
1966
|
+
without it Whisper auto-detects and frequently hallucinates
|
|
1967
|
+
outro phrases ("Thank you for watching") on silent clips.
|
|
1968
|
+
|
|
1969
|
+
Returns:
|
|
1970
|
+
{"text": str, "duration_seconds": float, "credits_consumed": float}
|
|
1971
|
+
"""
|
|
1972
|
+
params: Dict[str, Any] = {
|
|
1973
|
+
"tenant_id": self.tenant_id,
|
|
1974
|
+
"duration_ms": duration_ms,
|
|
1975
|
+
}
|
|
1976
|
+
if user_id:
|
|
1977
|
+
params["user_id"] = user_id
|
|
1978
|
+
if language:
|
|
1979
|
+
params["language"] = language
|
|
1980
|
+
return await self._request_post_multipart(
|
|
1981
|
+
endpoint="transcribe_v1",
|
|
1982
|
+
params=params,
|
|
1983
|
+
file_field="audio",
|
|
1984
|
+
file_name="audio.webm",
|
|
1985
|
+
file_data=audio_bytes,
|
|
1986
|
+
content_type=mime_type,
|
|
1987
|
+
api_base=self.voice_api_base,
|
|
1988
|
+
)
|
|
1989
|
+
|