agentrun-inner-test 0.0.46__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.
Files changed (135) hide show
  1. agentrun/__init__.py +325 -0
  2. agentrun/agent_runtime/__client_async_template.py +466 -0
  3. agentrun/agent_runtime/__endpoint_async_template.py +345 -0
  4. agentrun/agent_runtime/__init__.py +53 -0
  5. agentrun/agent_runtime/__runtime_async_template.py +477 -0
  6. agentrun/agent_runtime/api/__data_async_template.py +58 -0
  7. agentrun/agent_runtime/api/__init__.py +6 -0
  8. agentrun/agent_runtime/api/control.py +1362 -0
  9. agentrun/agent_runtime/api/data.py +98 -0
  10. agentrun/agent_runtime/client.py +868 -0
  11. agentrun/agent_runtime/endpoint.py +649 -0
  12. agentrun/agent_runtime/model.py +362 -0
  13. agentrun/agent_runtime/runtime.py +904 -0
  14. agentrun/credential/__client_async_template.py +177 -0
  15. agentrun/credential/__credential_async_template.py +216 -0
  16. agentrun/credential/__init__.py +28 -0
  17. agentrun/credential/api/__init__.py +5 -0
  18. agentrun/credential/api/control.py +606 -0
  19. agentrun/credential/client.py +319 -0
  20. agentrun/credential/credential.py +381 -0
  21. agentrun/credential/model.py +248 -0
  22. agentrun/integration/__init__.py +21 -0
  23. agentrun/integration/agentscope/__init__.py +12 -0
  24. agentrun/integration/agentscope/adapter.py +17 -0
  25. agentrun/integration/agentscope/builtin.py +65 -0
  26. agentrun/integration/agentscope/message_adapter.py +185 -0
  27. agentrun/integration/agentscope/model_adapter.py +60 -0
  28. agentrun/integration/agentscope/tool_adapter.py +59 -0
  29. agentrun/integration/builtin/__init__.py +16 -0
  30. agentrun/integration/builtin/model.py +93 -0
  31. agentrun/integration/builtin/sandbox.py +1234 -0
  32. agentrun/integration/builtin/toolset.py +47 -0
  33. agentrun/integration/crewai/__init__.py +12 -0
  34. agentrun/integration/crewai/adapter.py +9 -0
  35. agentrun/integration/crewai/builtin.py +65 -0
  36. agentrun/integration/crewai/model_adapter.py +31 -0
  37. agentrun/integration/crewai/tool_adapter.py +26 -0
  38. agentrun/integration/google_adk/__init__.py +12 -0
  39. agentrun/integration/google_adk/adapter.py +15 -0
  40. agentrun/integration/google_adk/builtin.py +65 -0
  41. agentrun/integration/google_adk/message_adapter.py +144 -0
  42. agentrun/integration/google_adk/model_adapter.py +46 -0
  43. agentrun/integration/google_adk/tool_adapter.py +235 -0
  44. agentrun/integration/langchain/__init__.py +30 -0
  45. agentrun/integration/langchain/adapter.py +15 -0
  46. agentrun/integration/langchain/builtin.py +71 -0
  47. agentrun/integration/langchain/message_adapter.py +141 -0
  48. agentrun/integration/langchain/model_adapter.py +37 -0
  49. agentrun/integration/langchain/tool_adapter.py +50 -0
  50. agentrun/integration/langgraph/__init__.py +35 -0
  51. agentrun/integration/langgraph/adapter.py +20 -0
  52. agentrun/integration/langgraph/agent_converter.py +1073 -0
  53. agentrun/integration/langgraph/builtin.py +65 -0
  54. agentrun/integration/pydantic_ai/__init__.py +12 -0
  55. agentrun/integration/pydantic_ai/adapter.py +13 -0
  56. agentrun/integration/pydantic_ai/builtin.py +65 -0
  57. agentrun/integration/pydantic_ai/model_adapter.py +44 -0
  58. agentrun/integration/pydantic_ai/tool_adapter.py +19 -0
  59. agentrun/integration/utils/__init__.py +112 -0
  60. agentrun/integration/utils/adapter.py +560 -0
  61. agentrun/integration/utils/canonical.py +164 -0
  62. agentrun/integration/utils/converter.py +134 -0
  63. agentrun/integration/utils/model.py +110 -0
  64. agentrun/integration/utils/tool.py +1759 -0
  65. agentrun/model/__client_async_template.py +357 -0
  66. agentrun/model/__init__.py +57 -0
  67. agentrun/model/__model_proxy_async_template.py +270 -0
  68. agentrun/model/__model_service_async_template.py +267 -0
  69. agentrun/model/api/__init__.py +6 -0
  70. agentrun/model/api/control.py +1173 -0
  71. agentrun/model/api/data.py +196 -0
  72. agentrun/model/client.py +674 -0
  73. agentrun/model/model.py +235 -0
  74. agentrun/model/model_proxy.py +439 -0
  75. agentrun/model/model_service.py +438 -0
  76. agentrun/sandbox/__aio_sandbox_async_template.py +523 -0
  77. agentrun/sandbox/__browser_sandbox_async_template.py +110 -0
  78. agentrun/sandbox/__client_async_template.py +491 -0
  79. agentrun/sandbox/__code_interpreter_sandbox_async_template.py +463 -0
  80. agentrun/sandbox/__init__.py +69 -0
  81. agentrun/sandbox/__sandbox_async_template.py +463 -0
  82. agentrun/sandbox/__template_async_template.py +152 -0
  83. agentrun/sandbox/aio_sandbox.py +905 -0
  84. agentrun/sandbox/api/__aio_data_async_template.py +335 -0
  85. agentrun/sandbox/api/__browser_data_async_template.py +140 -0
  86. agentrun/sandbox/api/__code_interpreter_data_async_template.py +206 -0
  87. agentrun/sandbox/api/__init__.py +19 -0
  88. agentrun/sandbox/api/__sandbox_data_async_template.py +107 -0
  89. agentrun/sandbox/api/aio_data.py +551 -0
  90. agentrun/sandbox/api/browser_data.py +172 -0
  91. agentrun/sandbox/api/code_interpreter_data.py +396 -0
  92. agentrun/sandbox/api/control.py +1051 -0
  93. agentrun/sandbox/api/playwright_async.py +492 -0
  94. agentrun/sandbox/api/playwright_sync.py +492 -0
  95. agentrun/sandbox/api/sandbox_data.py +154 -0
  96. agentrun/sandbox/browser_sandbox.py +185 -0
  97. agentrun/sandbox/client.py +925 -0
  98. agentrun/sandbox/code_interpreter_sandbox.py +823 -0
  99. agentrun/sandbox/model.py +397 -0
  100. agentrun/sandbox/sandbox.py +848 -0
  101. agentrun/sandbox/template.py +217 -0
  102. agentrun/server/__init__.py +191 -0
  103. agentrun/server/agui_normalizer.py +180 -0
  104. agentrun/server/agui_protocol.py +797 -0
  105. agentrun/server/invoker.py +309 -0
  106. agentrun/server/model.py +427 -0
  107. agentrun/server/openai_protocol.py +535 -0
  108. agentrun/server/protocol.py +140 -0
  109. agentrun/server/server.py +208 -0
  110. agentrun/toolset/__client_async_template.py +62 -0
  111. agentrun/toolset/__init__.py +51 -0
  112. agentrun/toolset/__toolset_async_template.py +204 -0
  113. agentrun/toolset/api/__init__.py +17 -0
  114. agentrun/toolset/api/control.py +262 -0
  115. agentrun/toolset/api/mcp.py +100 -0
  116. agentrun/toolset/api/openapi.py +1251 -0
  117. agentrun/toolset/client.py +102 -0
  118. agentrun/toolset/model.py +321 -0
  119. agentrun/toolset/toolset.py +270 -0
  120. agentrun/utils/__data_api_async_template.py +720 -0
  121. agentrun/utils/__init__.py +5 -0
  122. agentrun/utils/__resource_async_template.py +158 -0
  123. agentrun/utils/config.py +258 -0
  124. agentrun/utils/control_api.py +78 -0
  125. agentrun/utils/data_api.py +1120 -0
  126. agentrun/utils/exception.py +151 -0
  127. agentrun/utils/helper.py +108 -0
  128. agentrun/utils/log.py +77 -0
  129. agentrun/utils/model.py +168 -0
  130. agentrun/utils/resource.py +291 -0
  131. agentrun_inner_test-0.0.46.dist-info/METADATA +263 -0
  132. agentrun_inner_test-0.0.46.dist-info/RECORD +135 -0
  133. agentrun_inner_test-0.0.46.dist-info/WHEEL +5 -0
  134. agentrun_inner_test-0.0.46.dist-info/licenses/LICENSE +201 -0
  135. agentrun_inner_test-0.0.46.dist-info/top_level.txt +1 -0
@@ -0,0 +1,720 @@
1
+ """AgentRun Data Client SDK / AgentRun 数据客户端 SDK
2
+
3
+ This module provides an async HTTP client for interacting with the AgentRun Data API.
4
+ 此模块提供用于与 AgentRun Data API 交互的异步 HTTP 客户端。
5
+
6
+ It supports standard HTTP methods (GET, POST, PUT, PATCH, DELETE) with proper
7
+ error handling, type hints, and JSON serialization.
8
+ """
9
+
10
+ from enum import Enum
11
+ from typing import Any, Dict, Optional, Union
12
+ from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
13
+
14
+ import httpx
15
+
16
+ from agentrun.utils.config import Config
17
+ from agentrun.utils.exception import ClientError
18
+ from agentrun.utils.helper import mask_password
19
+ from agentrun.utils.log import logger
20
+
21
+
22
+ class ResourceType(Enum):
23
+ Runtime = "runtime"
24
+ LiteLLM = "litellm"
25
+ Tool = "tool"
26
+ Template = "template"
27
+ Sandbox = "sandbox"
28
+
29
+
30
+ class DataAPI:
31
+ """
32
+ Async HTTP client for AgentRun Data API.
33
+
34
+ This client provides async methods for making HTTP requests to the AgentRun Data API
35
+ with automatic URL construction, JSON handling, and error management.
36
+
37
+ The client automatically manages HTTP sessions - no need for manual session management
38
+ or context managers in simple use cases.
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ resource_name: str,
44
+ resource_type: ResourceType,
45
+ config: Optional[Config] = None,
46
+ namespace: str = "agents",
47
+ ):
48
+ """
49
+ Initialize the AgentRun Data Client.
50
+
51
+ Args:
52
+ region: Aliyun region (default: "cn-hangzhou")
53
+ protocol: Protocol to use (default: "https")
54
+ account_id: Aliyun account ID
55
+ version: API version (default: "2025-09-10")
56
+ namespace: API namespace (default: "agents")
57
+ timeout: Request timeout in seconds (default: 600)
58
+ headers: Default headers to include in all requests
59
+ auto_manage_session: Whether to automatically manage sessions (default: True)
60
+
61
+ Raises:
62
+ ValueError: If account_id is not provided or protocol is invalid
63
+ """
64
+
65
+ self.resource_name = resource_name
66
+ self.resource_type = resource_type
67
+ self.access_token = None
68
+
69
+ self.config = Config.with_configs(config)
70
+ self.namespace = namespace
71
+
72
+ if self.config.get_token():
73
+ logger.debug(
74
+ "using provided access token from config, %s",
75
+ mask_password(self.config.get_token() or ""),
76
+ )
77
+ self.access_token = self.config.get_token()
78
+
79
+ def get_base_url(self) -> str:
80
+ """
81
+ Get the base URL for API requests.
82
+
83
+ Returns:
84
+ The base URL string
85
+ """
86
+ return self.config.get_data_endpoint()
87
+
88
+ def with_path(
89
+ self, path: str, query: Optional[Dict[str, Any]] = None
90
+ ) -> str:
91
+ """
92
+ Construct full URL with the given path and query parameters.
93
+
94
+ Args:
95
+ path: API path (may include query string)
96
+ query: Query parameters to add/merge
97
+
98
+ Returns:
99
+ Complete URL string with query parameters
100
+
101
+ Examples:
102
+ >>> client.with_path("resources")
103
+ "http://account.agentrun-data.cn-hangzhou.aliyuncs.com/2025-09-10/agents/resources"
104
+
105
+ >>> client.with_path("resources", {"limit": 10})
106
+ "http://account.agentrun-data.cn-hangzhou.aliyuncs.com/2025-09-10/agents/resources?limit=10"
107
+
108
+ >>> client.with_path("resources?page=1", {"limit": 10})
109
+ "http://account.agentrun-data.cn-hangzhou.aliyuncs.com/2025-09-10/agents/resources?page=1&limit=10"
110
+ """
111
+ # Remove leading slash if present
112
+ path = path.lstrip("/")
113
+ base_url = "/".join([
114
+ part.strip("/")
115
+ for part in [
116
+ self.get_base_url(),
117
+ self.namespace,
118
+ path,
119
+ ]
120
+ if part
121
+ ])
122
+
123
+ # If no query parameters, return the base URL
124
+ if not query:
125
+ return base_url
126
+
127
+ # Parse the URL to handle existing query parameters
128
+ parsed = urlparse(base_url)
129
+
130
+ # Parse existing query parameters
131
+ existing_params = parse_qs(parsed.query, keep_blank_values=True)
132
+
133
+ # Merge with new query parameters
134
+ # Convert new query dict to the same format as parse_qs (values as lists)
135
+ for key, value in query.items():
136
+ if isinstance(value, list):
137
+ existing_params[key] = value
138
+ else:
139
+ existing_params[key] = [str(value)]
140
+
141
+ # Flatten the parameters (convert lists to single values where appropriate)
142
+ flattened_params = {}
143
+ for key, value_list in existing_params.items():
144
+ if len(value_list) == 1:
145
+ flattened_params[key] = value_list[0]
146
+ else:
147
+ flattened_params[key] = value_list
148
+
149
+ # Encode query string
150
+ new_query = urlencode(flattened_params, doseq=True)
151
+
152
+ # Reconstruct URL with new query string
153
+ return urlunparse((
154
+ parsed.scheme,
155
+ parsed.netloc,
156
+ parsed.path,
157
+ parsed.params,
158
+ new_query,
159
+ parsed.fragment,
160
+ ))
161
+
162
+ def auth(
163
+ self,
164
+ url: str = "",
165
+ headers: Optional[Dict[str, str]] = None,
166
+ query: Optional[Dict[str, Any]] = None,
167
+ config: Optional[Config] = None,
168
+ ) -> tuple[str, Dict[str, str], Optional[Dict[str, Any]]]:
169
+ """
170
+ Authentication hook for modifying requests before sending.
171
+
172
+ This method can be overridden in subclasses to implement custom
173
+ authentication logic (e.g., signing requests, adding auth tokens).
174
+
175
+ Args:
176
+ url: The request URL
177
+ headers: The request headers
178
+ query: The query parameters
179
+
180
+ Returns:
181
+ Tuple of (modified_url, modified_headers, modified_query)
182
+
183
+ Examples:
184
+ Override this method to add custom authentication:
185
+
186
+ >>> class AuthedClient(AgentRunDataClient):
187
+ ... def auth(self, url, headers, query):
188
+ ... # Add auth token to headers
189
+ ... headers["Authorization"] = "Bearer token123"
190
+ ... # Or add signature to query
191
+ ... query = query or {}
192
+ ... query["signature"] = self._sign_request(url)
193
+ ... return url, headers, query
194
+ """
195
+ cfg = Config.with_configs(self.config, config)
196
+
197
+ if (
198
+ self.access_token is None
199
+ and self.resource_name
200
+ and self.resource_type
201
+ and not cfg.get_token()
202
+ ):
203
+ try:
204
+ from alibabacloud_agentrun20250910.models import (
205
+ GetAccessTokenRequest,
206
+ )
207
+
208
+ from .control_api import ControlAPI
209
+
210
+ cli = ControlAPI(self.config)._get_client()
211
+ input = (
212
+ GetAccessTokenRequest(
213
+ resource_id=self.resource_name,
214
+ resource_type=self.resource_type.value,
215
+ )
216
+ if self.resource_type == ResourceType.Sandbox
217
+ else GetAccessTokenRequest(
218
+ resource_name=self.resource_name,
219
+ resource_type=self.resource_type.value,
220
+ )
221
+ )
222
+
223
+ resp = cli.get_access_token(input)
224
+ self.access_token = resp.body.data.access_token
225
+
226
+ except Exception as e:
227
+ logger.warning(
228
+ "Failed to get access token for"
229
+ f" {self.resource_type}({self.resource_name}): {e}"
230
+ )
231
+
232
+ logger.debug(
233
+ "fetching access token for resource %s of type %s, %s",
234
+ self.resource_name,
235
+ self.resource_type,
236
+ mask_password(self.access_token or ""),
237
+ )
238
+ headers = {
239
+ "Agentrun-Access-Token": cfg.get_token() or self.access_token or "",
240
+ **cfg.get_headers(),
241
+ **(headers or {}),
242
+ }
243
+
244
+ return url, headers, query
245
+
246
+ def _prepare_request(
247
+ self,
248
+ method: str,
249
+ url: str,
250
+ data: Optional[Union[Dict[str, Any], str]] = None,
251
+ headers: Optional[Dict[str, str]] = None,
252
+ query: Optional[Dict[str, Any]] = None,
253
+ config: Optional[Config] = None,
254
+ ):
255
+ req_headers = {
256
+ "Content-Type": "application/json",
257
+ "User-Agent": "AgentRunDataClient/1.0",
258
+ }
259
+
260
+ # Merge with instance default headers
261
+ cfg = Config.with_configs(self.config, config)
262
+
263
+ req_headers.update(cfg.get_headers())
264
+
265
+ # Merge request-specific headers
266
+ if headers:
267
+ req_headers.update(headers)
268
+
269
+ # Apply authentication (may modify URL, headers, and query)
270
+ url, req_headers, query = self.auth(url, req_headers, query, config=cfg)
271
+
272
+ # Add query parameters to URL if provided
273
+ if query:
274
+ parsed = urlparse(url)
275
+ existing_params = parse_qs(parsed.query, keep_blank_values=True)
276
+
277
+ # Merge query parameters
278
+ for key, value in query.items():
279
+ if isinstance(value, list):
280
+ existing_params[key] = value
281
+ else:
282
+ existing_params[key] = [str(value)]
283
+
284
+ # Flatten and encode
285
+ flattened_params = {}
286
+ for key, value_list in existing_params.items():
287
+ if len(value_list) == 1:
288
+ flattened_params[key] = value_list[0]
289
+ else:
290
+ flattened_params[key] = value_list
291
+
292
+ new_query = urlencode(flattened_params, doseq=True)
293
+ url = urlunparse((
294
+ parsed.scheme,
295
+ parsed.netloc,
296
+ parsed.path,
297
+ parsed.params,
298
+ new_query,
299
+ parsed.fragment,
300
+ ))
301
+
302
+ # Prepare request body
303
+ req_json = None
304
+ req_content = None
305
+
306
+ if data is not None:
307
+ if isinstance(data, dict):
308
+ req_json = data
309
+ elif isinstance(data, str):
310
+ req_content = data
311
+ else:
312
+ req_content = str(data)
313
+
314
+ logger.debug(
315
+ "%s %s headers=%s, json=%s, content=%s",
316
+ method,
317
+ url,
318
+ req_headers,
319
+ req_json,
320
+ req_content,
321
+ )
322
+ return method, url, req_headers, req_json, req_content
323
+
324
+ async def _make_request_async(
325
+ self,
326
+ method: str,
327
+ url: str,
328
+ data: Optional[Union[Dict[str, Any], str]] = None,
329
+ headers: Optional[Dict[str, str]] = None,
330
+ query: Optional[Dict[str, Any]] = None,
331
+ config: Optional[Config] = None,
332
+ ) -> Dict[str, Any]:
333
+ """
334
+ Make a sync HTTP request using httpx.
335
+
336
+ Args:
337
+ method: HTTP method (GET, POST, PUT, PATCH, DELETE)
338
+ url: Full URL to request
339
+ data: Request body (dict or string)
340
+ headers: Additional headers to include
341
+ query: Query parameters to add to URL
342
+
343
+ Returns:
344
+ Response body as dictionary
345
+
346
+ Raises:
347
+ AgentRunClientError: If the request fails
348
+ """
349
+ method, url, req_headers, req_json, req_content = self._prepare_request(
350
+ method, url, data, headers, query, config=config
351
+ )
352
+
353
+ try:
354
+ async with httpx.AsyncClient(
355
+ timeout=self.config.get_timeout()
356
+ ) as client:
357
+ response = await client.request(
358
+ method,
359
+ url,
360
+ headers=req_headers,
361
+ json=req_json,
362
+ content=req_content,
363
+ )
364
+
365
+ # # Raise for HTTP error status codes
366
+ # response.raise_for_status()
367
+
368
+ response_text = response.text
369
+ logger.debug(f"Response: {response_text}")
370
+
371
+ # Parse JSON response
372
+ if response_text:
373
+ try:
374
+ return response.json()
375
+ except ValueError as e:
376
+ error_msg = f"Failed to parse JSON response: {e}"
377
+ bad_gateway_error_message = "502 Bad Gateway"
378
+ if response.status_code == 502 and (
379
+ bad_gateway_error_message in response_text
380
+ ):
381
+ error_msg = bad_gateway_error_message
382
+ logger.error(error_msg)
383
+ raise ClientError(
384
+ status_code=response.status_code, message=error_msg
385
+ ) from e
386
+
387
+ return {}
388
+
389
+ except httpx.HTTPStatusError as e:
390
+ # HTTP error response
391
+ error_text = ""
392
+ try:
393
+ error_text = e.response.text
394
+ except Exception:
395
+ error_text = str(e)
396
+
397
+ error_msg = (
398
+ f"HTTP {e.response.status_code} error:"
399
+ f" {error_text or e.response.reason_phrase}"
400
+ )
401
+ raise ClientError(
402
+ status_code=e.response.status_code, message=error_msg
403
+ ) from e
404
+
405
+ except httpx.RequestError as e:
406
+ error_msg = f"Request error: {e!s}"
407
+ raise ClientError(status_code=0, message=error_msg) from e
408
+
409
+ async def get_async(
410
+ self,
411
+ path: str,
412
+ query: Optional[Dict[str, Any]] = None,
413
+ headers: Optional[Dict[str, str]] = None,
414
+ config: Optional[Config] = None,
415
+ ) -> Dict[str, Any]:
416
+ """
417
+ Make an async GET request.
418
+
419
+ Args:
420
+ path: API path (may include query string)
421
+ query: Query parameters to add/merge
422
+ headers: Additional headers
423
+
424
+ Returns:
425
+ Response body as dictionary
426
+
427
+ Raises:
428
+ AgentRunClientError: If the request fails
429
+
430
+ Examples:
431
+ >>> await client.get("resources")
432
+ >>> await client.get("resources", query={"limit": 10, "page": 1})
433
+ >>> await client.get("resources?status=active", query={"limit": 10})
434
+ """
435
+ return await self._make_request_async(
436
+ "GET",
437
+ self.with_path(path, query=query),
438
+ headers=headers,
439
+ config=config,
440
+ )
441
+
442
+ async def post_async(
443
+ self,
444
+ path: str,
445
+ data: Optional[Union[Dict[str, Any], str]] = None,
446
+ query: Optional[Dict[str, Any]] = None,
447
+ headers: Optional[Dict[str, str]] = None,
448
+ config: Optional[Config] = None,
449
+ ) -> Dict[str, Any]:
450
+ """
451
+ Make an async POST request.
452
+
453
+ Args:
454
+ path: API path (may include query string)
455
+ data: Request body
456
+ query: Query parameters to add/merge
457
+ headers: Additional headers
458
+
459
+ Returns:
460
+ Response body as dictionary
461
+
462
+ Raises:
463
+ AgentRunClientError: If the request fails
464
+
465
+ Examples:
466
+ >>> await client.post("resources", data={"name": "test"})
467
+ >>> await client.post("resources", data={"name": "test"}, query={"async": "true"})
468
+ """
469
+
470
+ return await self._make_request_async(
471
+ "POST",
472
+ self.with_path(path, query=query),
473
+ data=data,
474
+ headers=headers,
475
+ config=config,
476
+ )
477
+
478
+ async def put_async(
479
+ self,
480
+ path: str,
481
+ data: Optional[Union[Dict[str, Any], str]] = None,
482
+ query: Optional[Dict[str, Any]] = None,
483
+ headers: Optional[Dict[str, str]] = None,
484
+ config: Optional[Config] = None,
485
+ ) -> Dict[str, Any]:
486
+ """
487
+ Make an async PUT request.
488
+
489
+ Args:
490
+ path: API path (may include query string)
491
+ data: Request body
492
+ query: Query parameters to add/merge
493
+ headers: Additional headers
494
+
495
+ Returns:
496
+ Response body as dictionary
497
+
498
+ Raises:
499
+ AgentRunClientError: If the request fails
500
+ """
501
+ return await self._make_request_async(
502
+ "PUT",
503
+ self.with_path(path, query=query),
504
+ data=data,
505
+ headers=headers,
506
+ config=config,
507
+ )
508
+
509
+ async def patch_async(
510
+ self,
511
+ path: str,
512
+ data: Optional[Union[Dict[str, Any], str]] = None,
513
+ query: Optional[Dict[str, Any]] = None,
514
+ headers: Optional[Dict[str, str]] = None,
515
+ config: Optional[Config] = None,
516
+ ) -> Dict[str, Any]:
517
+ """
518
+ Make an async PATCH request.
519
+
520
+ Args:
521
+ path: API path (may include query string)
522
+ data: Request body
523
+ query: Query parameters to add/merge
524
+ headers: Additional headers
525
+
526
+ Returns:
527
+ Response body as dictionary
528
+
529
+ Raises:
530
+ AgentRunClientError: If the request fails
531
+ """
532
+ return await self._make_request_async(
533
+ "PATCH",
534
+ self.with_path(path, query=query),
535
+ data=data,
536
+ headers=headers,
537
+ config=config,
538
+ )
539
+
540
+ async def delete_async(
541
+ self,
542
+ path: str,
543
+ query: Optional[Dict[str, Any]] = None,
544
+ headers: Optional[Dict[str, str]] = None,
545
+ config: Optional[Config] = None,
546
+ ) -> Dict[str, Any]:
547
+ """
548
+ Make an async DELETE request.
549
+
550
+ Args:
551
+ path: API path (may include query string)
552
+ query: Query parameters to add/merge
553
+ headers: Additional headers
554
+
555
+ Returns:
556
+ Response body as dictionary
557
+
558
+ Raises:
559
+ AgentRunClientError: If the request fails
560
+ """
561
+ return await self._make_request_async(
562
+ "DELETE",
563
+ self.with_path(path, query=query),
564
+ headers=headers,
565
+ config=config,
566
+ )
567
+
568
+ async def post_file_async(
569
+ self,
570
+ path: str,
571
+ local_file_path: str,
572
+ target_file_path: str,
573
+ form_data: Optional[Dict[str, Any]] = None,
574
+ query: Optional[Dict[str, Any]] = None,
575
+ headers: Optional[Dict[str, str]] = None,
576
+ config: Optional[Config] = None,
577
+ ) -> Dict[str, Any]:
578
+ """
579
+ Asynchronously upload a file using multipart/form-data (POST request).
580
+
581
+ Args:
582
+ path: API path (may include query string)
583
+ local_file_path: Local file path to upload
584
+ target_file_path: Target file path on the server
585
+ form_data: Additional form data fields
586
+ query: Query parameters to add/merge
587
+ headers: Additional headers
588
+
589
+ Returns:
590
+ Response body as dictionary
591
+
592
+ Raises:
593
+ AgentRunClientError: If the request fails
594
+
595
+ Examples:
596
+ >>> await client.post_file_async("/files", local_file_path="/local/data.csv", target_file_path="/remote/data.csv")
597
+ >>> await client.post_file_async("/files", local_file_path="/local/data.csv", target_file_path="/remote/input.csv")
598
+ """
599
+ import os
600
+
601
+ filename = os.path.basename(local_file_path)
602
+
603
+ url = self.with_path(path, query=query)
604
+ req_headers = self.config.get_headers()
605
+ req_headers.update(headers or {})
606
+
607
+ try:
608
+ with open(local_file_path, "rb") as f:
609
+ file_content = f.read()
610
+ files = {"file": (filename, file_content)}
611
+ data = form_data or {}
612
+ data["path"] = target_file_path
613
+
614
+ async with httpx.AsyncClient(
615
+ timeout=self.config.get_timeout()
616
+ ) as client:
617
+ response = await client.post(
618
+ url, files=files, data=data, headers=req_headers
619
+ )
620
+ response.raise_for_status()
621
+ return response.json()
622
+ except httpx.HTTPStatusError as e:
623
+ raise ClientError(
624
+ status_code=e.response.status_code, message=e.response.text
625
+ ) from e
626
+
627
+ async def get_file_async(
628
+ self,
629
+ path: str,
630
+ save_path: str,
631
+ query: Optional[Dict[str, Any]] = None,
632
+ headers: Optional[Dict[str, str]] = None,
633
+ config: Optional[Config] = None,
634
+ ) -> Dict[str, Any]:
635
+ """
636
+ Asynchronously download a file and save it to local path (GET request).
637
+
638
+ Args:
639
+ path: API path (may include query string)
640
+ save_path: Local file path to save the downloaded file
641
+ query: Query parameters to add/merge
642
+ headers: Additional headers
643
+
644
+ Returns:
645
+ Dictionary with 'saved_path' and 'size' keys
646
+
647
+ Raises:
648
+ AgentRunClientError: If the request fails
649
+
650
+ Examples:
651
+ >>> await client.get_file_async("/files", save_path="/local/data.csv", query={"path": "/remote/file.csv"})
652
+ """
653
+ url = self.with_path(path, query=query)
654
+ req_headers = self.config.get_headers()
655
+ req_headers.update(headers or {})
656
+
657
+ try:
658
+ async with httpx.AsyncClient(
659
+ timeout=self.config.get_timeout()
660
+ ) as client:
661
+ response = await client.get(url, headers=req_headers)
662
+ response.raise_for_status()
663
+
664
+ with open(save_path, "wb") as f:
665
+ f.write(response.content)
666
+
667
+ return {"saved_path": save_path, "size": len(response.content)}
668
+ except httpx.HTTPStatusError as e:
669
+ raise ClientError(
670
+ status_code=e.response.status_code, message=e.response.text
671
+ ) from e
672
+
673
+ async def get_video_async(
674
+ self,
675
+ path: str,
676
+ save_path: str,
677
+ query: Optional[Dict[str, Any]] = None,
678
+ headers: Optional[Dict[str, str]] = None,
679
+ config: Optional[Config] = None,
680
+ ) -> Dict[str, Any]:
681
+ """
682
+ Asynchronously download a video file and save it to local path (GET request).
683
+
684
+ Args:
685
+ path: API path (may include query string)
686
+ save_path: Local file path to save the downloaded video file (.mkv)
687
+ query: Query parameters to add/merge
688
+ headers: Additional headers
689
+
690
+ Returns:
691
+ Dictionary with 'saved_path' and 'size' keys
692
+
693
+ Raises:
694
+ AgentRunClientError: If the request fails
695
+
696
+ Examples:
697
+ >>> await client.get_video_async("/videos", save_path="/local/video.mkv", query={"path": "/remote/video.mp4"})
698
+ """
699
+ url = self.with_path(path, query=query)
700
+ req_headers = self.config.get_headers()
701
+ req_headers.update(headers or {})
702
+ # Apply authentication (may modify URL, headers, and query)
703
+ cfg = Config.with_configs(self.config, config)
704
+ url, req_headers, query = self.auth(url, req_headers, query, config=cfg)
705
+
706
+ try:
707
+ async with httpx.AsyncClient(
708
+ timeout=self.config.get_timeout()
709
+ ) as client:
710
+ response = await client.get(url, headers=req_headers)
711
+ response.raise_for_status()
712
+
713
+ with open(save_path, "wb") as f:
714
+ f.write(response.content)
715
+
716
+ return {"saved_path": save_path, "size": len(response.content)}
717
+ except httpx.HTTPStatusError as e:
718
+ raise ClientError(
719
+ status_code=e.response.status_code, message=e.response.text
720
+ ) from e