agentrun-sdk 0.0.4__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 (128) hide show
  1. agentrun/__init__.py +209 -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 +97 -0
  31. agentrun/integration/builtin/sandbox.py +276 -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 +27 -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 +43 -0
  43. agentrun/integration/google_adk/tool_adapter.py +25 -0
  44. agentrun/integration/langchain/__init__.py +9 -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 +13 -0
  51. agentrun/integration/langgraph/adapter.py +20 -0
  52. agentrun/integration/langgraph/builtin.py +65 -0
  53. agentrun/integration/pydantic_ai/__init__.py +12 -0
  54. agentrun/integration/pydantic_ai/adapter.py +13 -0
  55. agentrun/integration/pydantic_ai/builtin.py +65 -0
  56. agentrun/integration/pydantic_ai/model_adapter.py +44 -0
  57. agentrun/integration/pydantic_ai/tool_adapter.py +19 -0
  58. agentrun/integration/utils/__init__.py +112 -0
  59. agentrun/integration/utils/adapter.py +167 -0
  60. agentrun/integration/utils/canonical.py +157 -0
  61. agentrun/integration/utils/converter.py +134 -0
  62. agentrun/integration/utils/model.py +107 -0
  63. agentrun/integration/utils/tool.py +1714 -0
  64. agentrun/model/__client_async_template.py +357 -0
  65. agentrun/model/__init__.py +57 -0
  66. agentrun/model/__model_proxy_async_template.py +270 -0
  67. agentrun/model/__model_service_async_template.py +267 -0
  68. agentrun/model/api/__init__.py +6 -0
  69. agentrun/model/api/control.py +1173 -0
  70. agentrun/model/api/data.py +196 -0
  71. agentrun/model/client.py +674 -0
  72. agentrun/model/model.py +218 -0
  73. agentrun/model/model_proxy.py +439 -0
  74. agentrun/model/model_service.py +438 -0
  75. agentrun/sandbox/__browser_sandbox_async_template.py +113 -0
  76. agentrun/sandbox/__client_async_template.py +466 -0
  77. agentrun/sandbox/__code_interpreter_sandbox_async_template.py +466 -0
  78. agentrun/sandbox/__init__.py +54 -0
  79. agentrun/sandbox/__sandbox_async_template.py +398 -0
  80. agentrun/sandbox/__template_async_template.py +150 -0
  81. agentrun/sandbox/api/__browser_data_async_template.py +140 -0
  82. agentrun/sandbox/api/__code_interpreter_data_async_template.py +206 -0
  83. agentrun/sandbox/api/__init__.py +17 -0
  84. agentrun/sandbox/api/__sandbox_data_async_template.py +100 -0
  85. agentrun/sandbox/api/browser_data.py +172 -0
  86. agentrun/sandbox/api/code_interpreter_data.py +396 -0
  87. agentrun/sandbox/api/control.py +1051 -0
  88. agentrun/sandbox/api/playwright_async.py +492 -0
  89. agentrun/sandbox/api/playwright_sync.py +492 -0
  90. agentrun/sandbox/api/sandbox_data.py +140 -0
  91. agentrun/sandbox/browser_sandbox.py +191 -0
  92. agentrun/sandbox/client.py +878 -0
  93. agentrun/sandbox/code_interpreter_sandbox.py +829 -0
  94. agentrun/sandbox/model.py +269 -0
  95. agentrun/sandbox/sandbox.py +737 -0
  96. agentrun/sandbox/template.py +215 -0
  97. agentrun/server/__init__.py +82 -0
  98. agentrun/server/invoker.py +131 -0
  99. agentrun/server/model.py +225 -0
  100. agentrun/server/openai_protocol.py +798 -0
  101. agentrun/server/protocol.py +96 -0
  102. agentrun/server/server.py +192 -0
  103. agentrun/toolset/__client_async_template.py +62 -0
  104. agentrun/toolset/__init__.py +51 -0
  105. agentrun/toolset/__toolset_async_template.py +204 -0
  106. agentrun/toolset/api/__init__.py +17 -0
  107. agentrun/toolset/api/control.py +262 -0
  108. agentrun/toolset/api/mcp.py +100 -0
  109. agentrun/toolset/api/openapi.py +1184 -0
  110. agentrun/toolset/client.py +102 -0
  111. agentrun/toolset/model.py +160 -0
  112. agentrun/toolset/toolset.py +271 -0
  113. agentrun/utils/__data_api_async_template.py +715 -0
  114. agentrun/utils/__init__.py +5 -0
  115. agentrun/utils/__resource_async_template.py +158 -0
  116. agentrun/utils/config.py +258 -0
  117. agentrun/utils/control_api.py +78 -0
  118. agentrun/utils/data_api.py +1110 -0
  119. agentrun/utils/exception.py +149 -0
  120. agentrun/utils/helper.py +34 -0
  121. agentrun/utils/log.py +77 -0
  122. agentrun/utils/model.py +168 -0
  123. agentrun/utils/resource.py +291 -0
  124. agentrun_sdk-0.0.4.dist-info/METADATA +262 -0
  125. agentrun_sdk-0.0.4.dist-info/RECORD +128 -0
  126. agentrun_sdk-0.0.4.dist-info/WHEEL +5 -0
  127. agentrun_sdk-0.0.4.dist-info/licenses/LICENSE +201 -0
  128. agentrun_sdk-0.0.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1110 @@
1
+ """
2
+ This file is auto generated by the code generation script.
3
+ Do not modify this file manually.
4
+ Use the `make codegen` command to regenerate.
5
+
6
+ 当前文件为自动生成的控制 API 客户端代码。请勿手动修改此文件。
7
+ 使用 `make codegen` 命令重新生成。
8
+
9
+ source: agentrun/utils/__data_api_async_template.py
10
+
11
+ AgentRun Data Client SDK / AgentRun 数据客户端 SDK
12
+
13
+ This module provides an async HTTP client for interacting with the AgentRun Data API.
14
+ 此模块提供用于与 AgentRun Data API 交互的异步 HTTP 客户端。
15
+
16
+ It supports standard HTTP methods (GET, POST, PUT, PATCH, DELETE) with proper
17
+ error handling, type hints, and JSON serialization.
18
+ """
19
+
20
+ from enum import Enum
21
+ from typing import Any, Dict, Optional, Union
22
+ from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
23
+
24
+ import httpx
25
+
26
+ from agentrun.utils.config import Config
27
+ from agentrun.utils.exception import ClientError
28
+ from agentrun.utils.helper import mask_password
29
+ from agentrun.utils.log import logger
30
+
31
+
32
+ class ResourceType(Enum):
33
+ Runtime = "runtime"
34
+ LiteLLM = "litellm"
35
+ Tool = "tool"
36
+ Template = "template"
37
+ Sandbox = "sandbox"
38
+
39
+
40
+ class DataAPI:
41
+ """
42
+ Async HTTP client for AgentRun Data API.
43
+
44
+ This client provides async methods for making HTTP requests to the AgentRun Data API
45
+ with automatic URL construction, JSON handling, and error management.
46
+
47
+ The client automatically manages HTTP sessions - no need for manual session management
48
+ or context managers in simple use cases.
49
+ """
50
+
51
+ def __init__(
52
+ self,
53
+ resource_name: str,
54
+ resource_type: ResourceType,
55
+ config: Optional[Config] = None,
56
+ namespace: str = "agents",
57
+ ):
58
+ """
59
+ Initialize the AgentRun Data Client.
60
+
61
+ Args:
62
+ region: Aliyun region (default: "cn-hangzhou")
63
+ protocol: Protocol to use (default: "https")
64
+ account_id: Aliyun account ID
65
+ version: API version (default: "2025-09-10")
66
+ namespace: API namespace (default: "agents")
67
+ timeout: Request timeout in seconds (default: 600)
68
+ headers: Default headers to include in all requests
69
+ auto_manage_session: Whether to automatically manage sessions (default: True)
70
+
71
+ Raises:
72
+ ValueError: If account_id is not provided or protocol is invalid
73
+ """
74
+
75
+ self.resource_name = resource_name
76
+ self.resource_type = resource_type
77
+ self.access_token = None
78
+
79
+ self.config = Config.with_configs(config)
80
+ self.namespace = namespace
81
+
82
+ if self.config.get_token():
83
+ logger.debug(
84
+ "using provided access token from config, %s",
85
+ mask_password(self.config.get_token() or ""),
86
+ )
87
+ self.access_token = self.config.get_token()
88
+
89
+ def get_base_url(self) -> str:
90
+ """
91
+ Get the base URL for API requests.
92
+
93
+ Returns:
94
+ The base URL string
95
+ """
96
+ return self.config.get_data_endpoint()
97
+
98
+ def with_path(
99
+ self, path: str, query: Optional[Dict[str, Any]] = None
100
+ ) -> str:
101
+ """
102
+ Construct full URL with the given path and query parameters.
103
+
104
+ Args:
105
+ path: API path (may include query string)
106
+ query: Query parameters to add/merge
107
+
108
+ Returns:
109
+ Complete URL string with query parameters
110
+
111
+ Examples:
112
+ >>> client.with_path("resources")
113
+ "http://account.agentrun-data.cn-hangzhou.aliyuncs.com/2025-09-10/agents/resources"
114
+
115
+ >>> client.with_path("resources", {"limit": 10})
116
+ "http://account.agentrun-data.cn-hangzhou.aliyuncs.com/2025-09-10/agents/resources?limit=10"
117
+
118
+ >>> client.with_path("resources?page=1", {"limit": 10})
119
+ "http://account.agentrun-data.cn-hangzhou.aliyuncs.com/2025-09-10/agents/resources?page=1&limit=10"
120
+ """
121
+ # Remove leading slash if present
122
+ path = path.lstrip("/")
123
+ base_url = "/".join([
124
+ part.strip("/")
125
+ for part in [
126
+ self.get_base_url(),
127
+ self.namespace,
128
+ path,
129
+ ]
130
+ if part
131
+ ])
132
+
133
+ # If no query parameters, return the base URL
134
+ if not query:
135
+ return base_url
136
+
137
+ # Parse the URL to handle existing query parameters
138
+ parsed = urlparse(base_url)
139
+
140
+ # Parse existing query parameters
141
+ existing_params = parse_qs(parsed.query, keep_blank_values=True)
142
+
143
+ # Merge with new query parameters
144
+ # Convert new query dict to the same format as parse_qs (values as lists)
145
+ for key, value in query.items():
146
+ if isinstance(value, list):
147
+ existing_params[key] = value
148
+ else:
149
+ existing_params[key] = [str(value)]
150
+
151
+ # Flatten the parameters (convert lists to single values where appropriate)
152
+ flattened_params = {}
153
+ for key, value_list in existing_params.items():
154
+ if len(value_list) == 1:
155
+ flattened_params[key] = value_list[0]
156
+ else:
157
+ flattened_params[key] = value_list
158
+
159
+ # Encode query string
160
+ new_query = urlencode(flattened_params, doseq=True)
161
+
162
+ # Reconstruct URL with new query string
163
+ return urlunparse((
164
+ parsed.scheme,
165
+ parsed.netloc,
166
+ parsed.path,
167
+ parsed.params,
168
+ new_query,
169
+ parsed.fragment,
170
+ ))
171
+
172
+ def auth(
173
+ self,
174
+ url: str = "",
175
+ headers: Optional[Dict[str, str]] = None,
176
+ query: Optional[Dict[str, Any]] = None,
177
+ config: Optional[Config] = None,
178
+ ) -> tuple[str, Dict[str, str], Optional[Dict[str, Any]]]:
179
+ """
180
+ Authentication hook for modifying requests before sending.
181
+
182
+ This method can be overridden in subclasses to implement custom
183
+ authentication logic (e.g., signing requests, adding auth tokens).
184
+
185
+ Args:
186
+ url: The request URL
187
+ headers: The request headers
188
+ query: The query parameters
189
+
190
+ Returns:
191
+ Tuple of (modified_url, modified_headers, modified_query)
192
+
193
+ Examples:
194
+ Override this method to add custom authentication:
195
+
196
+ >>> class AuthedClient(AgentRunDataClient):
197
+ ... def auth(self, url, headers, query):
198
+ ... # Add auth token to headers
199
+ ... headers["Authorization"] = "Bearer token123"
200
+ ... # Or add signature to query
201
+ ... query = query or {}
202
+ ... query["signature"] = self._sign_request(url)
203
+ ... return url, headers, query
204
+ """
205
+ cfg = Config.with_configs(self.config, config)
206
+
207
+ if (
208
+ self.access_token is None
209
+ and self.resource_name
210
+ and self.resource_type
211
+ and not cfg.get_token()
212
+ ):
213
+ try:
214
+ from alibabacloud_agentrun20250910.models import (
215
+ GetAccessTokenRequest,
216
+ )
217
+
218
+ from .control_api import ControlAPI
219
+
220
+ cli = ControlAPI(self.config)._get_client()
221
+ input = (
222
+ GetAccessTokenRequest(
223
+ resource_id=self.resource_name,
224
+ resource_type=self.resource_type.value,
225
+ )
226
+ if self.resource_type == ResourceType.Sandbox
227
+ else GetAccessTokenRequest(
228
+ resource_name=self.resource_name,
229
+ resource_type=self.resource_type.value,
230
+ )
231
+ )
232
+
233
+ resp = cli.get_access_token(input)
234
+ self.access_token = resp.body.data.access_token
235
+
236
+ except Exception as e:
237
+ logger.warning(
238
+ "Failed to get access token for"
239
+ f" {self.resource_type}({self.resource_name}): {e}"
240
+ )
241
+
242
+ logger.debug(
243
+ "fetching access token for resource %s of type %s, %s",
244
+ self.resource_name,
245
+ self.resource_type,
246
+ mask_password(self.access_token or ""),
247
+ )
248
+ headers = {
249
+ "Agentrun-Access-Token": cfg.get_token() or self.access_token or "",
250
+ **cfg.get_headers(),
251
+ **(headers or {}),
252
+ }
253
+
254
+ return url, headers, query
255
+
256
+ def _prepare_request(
257
+ self,
258
+ method: str,
259
+ url: str,
260
+ data: Optional[Union[Dict[str, Any], str]] = None,
261
+ headers: Optional[Dict[str, str]] = None,
262
+ query: Optional[Dict[str, Any]] = None,
263
+ config: Optional[Config] = None,
264
+ ):
265
+ req_headers = {
266
+ "Content-Type": "application/json",
267
+ "User-Agent": "AgentRunDataClient/1.0",
268
+ }
269
+
270
+ # Merge with instance default headers
271
+ cfg = Config.with_configs(self.config, config)
272
+
273
+ req_headers.update(cfg.get_headers())
274
+
275
+ # Merge request-specific headers
276
+ if headers:
277
+ req_headers.update(headers)
278
+
279
+ # Apply authentication (may modify URL, headers, and query)
280
+ url, req_headers, query = self.auth(url, req_headers, query, config=cfg)
281
+
282
+ # Add query parameters to URL if provided
283
+ if query:
284
+ parsed = urlparse(url)
285
+ existing_params = parse_qs(parsed.query, keep_blank_values=True)
286
+
287
+ # Merge query parameters
288
+ for key, value in query.items():
289
+ if isinstance(value, list):
290
+ existing_params[key] = value
291
+ else:
292
+ existing_params[key] = [str(value)]
293
+
294
+ # Flatten and encode
295
+ flattened_params = {}
296
+ for key, value_list in existing_params.items():
297
+ if len(value_list) == 1:
298
+ flattened_params[key] = value_list[0]
299
+ else:
300
+ flattened_params[key] = value_list
301
+
302
+ new_query = urlencode(flattened_params, doseq=True)
303
+ url = urlunparse((
304
+ parsed.scheme,
305
+ parsed.netloc,
306
+ parsed.path,
307
+ parsed.params,
308
+ new_query,
309
+ parsed.fragment,
310
+ ))
311
+
312
+ # Prepare request body
313
+ req_json = None
314
+ req_content = None
315
+
316
+ if data is not None:
317
+ if isinstance(data, dict):
318
+ req_json = data
319
+ elif isinstance(data, str):
320
+ req_content = data
321
+ else:
322
+ req_content = str(data)
323
+
324
+ logger.debug(
325
+ "%s %s headers=%s, json=%s, content=%s",
326
+ method,
327
+ url,
328
+ req_headers,
329
+ req_json,
330
+ req_content,
331
+ )
332
+ return method, url, req_headers, req_json, req_content
333
+
334
+ async def _make_request_async(
335
+ self,
336
+ method: str,
337
+ url: str,
338
+ data: Optional[Union[Dict[str, Any], str]] = None,
339
+ headers: Optional[Dict[str, str]] = None,
340
+ query: Optional[Dict[str, Any]] = None,
341
+ config: Optional[Config] = None,
342
+ ) -> Dict[str, Any]:
343
+ """
344
+ Make a sync HTTP request using httpx.
345
+
346
+ Args:
347
+ method: HTTP method (GET, POST, PUT, PATCH, DELETE)
348
+ url: Full URL to request
349
+ data: Request body (dict or string)
350
+ headers: Additional headers to include
351
+ query: Query parameters to add to URL
352
+
353
+ Returns:
354
+ Response body as dictionary
355
+
356
+ Raises:
357
+ AgentRunClientError: If the request fails
358
+ """
359
+ method, url, req_headers, req_json, req_content = self._prepare_request(
360
+ method, url, data, headers, query, config=config
361
+ )
362
+
363
+ try:
364
+ async with httpx.AsyncClient(
365
+ timeout=self.config.get_timeout()
366
+ ) as client:
367
+ response = await client.request(
368
+ method,
369
+ url,
370
+ headers=req_headers,
371
+ json=req_json,
372
+ content=req_content,
373
+ )
374
+
375
+ # # Raise for HTTP error status codes
376
+ # response.raise_for_status()
377
+
378
+ response_text = response.text
379
+ logger.debug(f"Response: {response_text}")
380
+
381
+ # Parse JSON response
382
+ if response_text:
383
+ try:
384
+ return response.json()
385
+ except ValueError as e:
386
+ error_msg = f"Failed to parse JSON response: {e}"
387
+ logger.error(error_msg)
388
+ raise ClientError(
389
+ status_code=response.status_code, message=error_msg
390
+ ) from e
391
+
392
+ return {}
393
+
394
+ except httpx.HTTPStatusError as e:
395
+ # HTTP error response
396
+ error_text = ""
397
+ try:
398
+ error_text = e.response.text
399
+ except Exception:
400
+ error_text = str(e)
401
+
402
+ error_msg = (
403
+ f"HTTP {e.response.status_code} error:"
404
+ f" {error_text or e.response.reason_phrase}"
405
+ )
406
+ raise ClientError(
407
+ status_code=e.response.status_code, message=error_msg
408
+ ) from e
409
+
410
+ except httpx.RequestError as e:
411
+ error_msg = f"Request error: {e!s}"
412
+ raise ClientError(status_code=0, message=error_msg) from e
413
+
414
+ def _make_request(
415
+ self,
416
+ method: str,
417
+ url: str,
418
+ data: Optional[Union[Dict[str, Any], str]] = None,
419
+ headers: Optional[Dict[str, str]] = None,
420
+ query: Optional[Dict[str, Any]] = None,
421
+ config: Optional[Config] = None,
422
+ ) -> Dict[str, Any]:
423
+ """
424
+ Make a sync HTTP request using httpx.
425
+
426
+ Args:
427
+ method: HTTP method (GET, POST, PUT, PATCH, DELETE)
428
+ url: Full URL to request
429
+ data: Request body (dict or string)
430
+ headers: Additional headers to include
431
+ query: Query parameters to add to URL
432
+
433
+ Returns:
434
+ Response body as dictionary
435
+
436
+ Raises:
437
+ AgentRunClientError: If the request fails
438
+ """
439
+ method, url, req_headers, req_json, req_content = self._prepare_request(
440
+ method, url, data, headers, query, config=config
441
+ )
442
+
443
+ try:
444
+ with httpx.Client(timeout=self.config.get_timeout()) as client:
445
+ response = client.request(
446
+ method,
447
+ url,
448
+ headers=req_headers,
449
+ json=req_json,
450
+ content=req_content,
451
+ )
452
+
453
+ # # Raise for HTTP error status codes
454
+ # response.raise_for_status()
455
+
456
+ response_text = response.text
457
+ logger.debug(f"Response: {response_text}")
458
+
459
+ # Parse JSON response
460
+ if response_text:
461
+ try:
462
+ return response.json()
463
+ except ValueError as e:
464
+ error_msg = f"Failed to parse JSON response: {e}"
465
+ logger.error(error_msg)
466
+ raise ClientError(
467
+ status_code=response.status_code, message=error_msg
468
+ ) from e
469
+
470
+ return {}
471
+
472
+ except httpx.HTTPStatusError as e:
473
+ # HTTP error response
474
+ error_text = ""
475
+ try:
476
+ error_text = e.response.text
477
+ except Exception:
478
+ error_text = str(e)
479
+
480
+ error_msg = (
481
+ f"HTTP {e.response.status_code} error:"
482
+ f" {error_text or e.response.reason_phrase}"
483
+ )
484
+ raise ClientError(
485
+ status_code=e.response.status_code, message=error_msg
486
+ ) from e
487
+
488
+ except httpx.RequestError as e:
489
+ error_msg = f"Request error: {e!s}"
490
+ raise ClientError(status_code=0, message=error_msg) from e
491
+
492
+ async def get_async(
493
+ self,
494
+ path: str,
495
+ query: Optional[Dict[str, Any]] = None,
496
+ headers: Optional[Dict[str, str]] = None,
497
+ config: Optional[Config] = None,
498
+ ) -> Dict[str, Any]:
499
+ """
500
+ Make an async GET request.
501
+
502
+ Args:
503
+ path: API path (may include query string)
504
+ query: Query parameters to add/merge
505
+ headers: Additional headers
506
+
507
+ Returns:
508
+ Response body as dictionary
509
+
510
+ Raises:
511
+ AgentRunClientError: If the request fails
512
+
513
+ Examples:
514
+ >>> await client.get("resources")
515
+ >>> await client.get("resources", query={"limit": 10, "page": 1})
516
+ >>> await client.get("resources?status=active", query={"limit": 10})
517
+ """
518
+ return await self._make_request_async(
519
+ "GET",
520
+ self.with_path(path, query=query),
521
+ headers=headers,
522
+ config=config,
523
+ )
524
+
525
+ def get(
526
+ self,
527
+ path: str,
528
+ query: Optional[Dict[str, Any]] = None,
529
+ headers: Optional[Dict[str, str]] = None,
530
+ config: Optional[Config] = None,
531
+ ) -> Dict[str, Any]:
532
+ """
533
+ Make an async GET request.
534
+
535
+ Args:
536
+ path: API path (may include query string)
537
+ query: Query parameters to add/merge
538
+ headers: Additional headers
539
+
540
+ Returns:
541
+ Response body as dictionary
542
+
543
+ Raises:
544
+ AgentRunClientError: If the request fails
545
+
546
+ Examples:
547
+ >>> client.get("resources")
548
+ >>> client.get("resources", query={"limit": 10, "page": 1})
549
+ >>> client.get("resources?status=active", query={"limit": 10})
550
+ """
551
+ return self._make_request(
552
+ "GET",
553
+ self.with_path(path, query=query),
554
+ headers=headers,
555
+ config=config,
556
+ )
557
+
558
+ async def post_async(
559
+ self,
560
+ path: str,
561
+ data: Optional[Union[Dict[str, Any], str]] = None,
562
+ query: Optional[Dict[str, Any]] = None,
563
+ headers: Optional[Dict[str, str]] = None,
564
+ config: Optional[Config] = None,
565
+ ) -> Dict[str, Any]:
566
+ """
567
+ Make an async POST request.
568
+
569
+ Args:
570
+ path: API path (may include query string)
571
+ data: Request body
572
+ query: Query parameters to add/merge
573
+ headers: Additional headers
574
+
575
+ Returns:
576
+ Response body as dictionary
577
+
578
+ Raises:
579
+ AgentRunClientError: If the request fails
580
+
581
+ Examples:
582
+ >>> await client.post("resources", data={"name": "test"})
583
+ >>> await client.post("resources", data={"name": "test"}, query={"async": "true"})
584
+ """
585
+
586
+ return await self._make_request_async(
587
+ "POST",
588
+ self.with_path(path, query=query),
589
+ data=data,
590
+ headers=headers,
591
+ config=config,
592
+ )
593
+
594
+ def post(
595
+ self,
596
+ path: str,
597
+ data: Optional[Union[Dict[str, Any], str]] = None,
598
+ query: Optional[Dict[str, Any]] = None,
599
+ headers: Optional[Dict[str, str]] = None,
600
+ config: Optional[Config] = None,
601
+ ) -> Dict[str, Any]:
602
+ """
603
+ Make an async POST request.
604
+
605
+ Args:
606
+ path: API path (may include query string)
607
+ data: Request body
608
+ query: Query parameters to add/merge
609
+ headers: Additional headers
610
+
611
+ Returns:
612
+ Response body as dictionary
613
+
614
+ Raises:
615
+ AgentRunClientError: If the request fails
616
+
617
+ Examples:
618
+ >>> client.post("resources", data={"name": "test"})
619
+ >>> client.post("resources", data={"name": "test"}, query={"async": "true"})
620
+ """
621
+
622
+ return self._make_request(
623
+ "POST",
624
+ self.with_path(path, query=query),
625
+ data=data,
626
+ headers=headers,
627
+ config=config,
628
+ )
629
+
630
+ async def put_async(
631
+ self,
632
+ path: str,
633
+ data: Optional[Union[Dict[str, Any], str]] = None,
634
+ query: Optional[Dict[str, Any]] = None,
635
+ headers: Optional[Dict[str, str]] = None,
636
+ config: Optional[Config] = None,
637
+ ) -> Dict[str, Any]:
638
+ """
639
+ Make an async PUT request.
640
+
641
+ Args:
642
+ path: API path (may include query string)
643
+ data: Request body
644
+ query: Query parameters to add/merge
645
+ headers: Additional headers
646
+
647
+ Returns:
648
+ Response body as dictionary
649
+
650
+ Raises:
651
+ AgentRunClientError: If the request fails
652
+ """
653
+ return await self._make_request_async(
654
+ "PUT",
655
+ self.with_path(path, query=query),
656
+ data=data,
657
+ headers=headers,
658
+ config=config,
659
+ )
660
+
661
+ def put(
662
+ self,
663
+ path: str,
664
+ data: Optional[Union[Dict[str, Any], str]] = None,
665
+ query: Optional[Dict[str, Any]] = None,
666
+ headers: Optional[Dict[str, str]] = None,
667
+ config: Optional[Config] = None,
668
+ ) -> Dict[str, Any]:
669
+ """
670
+ Make an async PUT request.
671
+
672
+ Args:
673
+ path: API path (may include query string)
674
+ data: Request body
675
+ query: Query parameters to add/merge
676
+ headers: Additional headers
677
+
678
+ Returns:
679
+ Response body as dictionary
680
+
681
+ Raises:
682
+ AgentRunClientError: If the request fails
683
+ """
684
+ return self._make_request(
685
+ "PUT",
686
+ self.with_path(path, query=query),
687
+ data=data,
688
+ headers=headers,
689
+ config=config,
690
+ )
691
+
692
+ async def patch_async(
693
+ self,
694
+ path: str,
695
+ data: Optional[Union[Dict[str, Any], str]] = None,
696
+ query: Optional[Dict[str, Any]] = None,
697
+ headers: Optional[Dict[str, str]] = None,
698
+ config: Optional[Config] = None,
699
+ ) -> Dict[str, Any]:
700
+ """
701
+ Make an async PATCH request.
702
+
703
+ Args:
704
+ path: API path (may include query string)
705
+ data: Request body
706
+ query: Query parameters to add/merge
707
+ headers: Additional headers
708
+
709
+ Returns:
710
+ Response body as dictionary
711
+
712
+ Raises:
713
+ AgentRunClientError: If the request fails
714
+ """
715
+ return await self._make_request_async(
716
+ "PATCH",
717
+ self.with_path(path, query=query),
718
+ data=data,
719
+ headers=headers,
720
+ config=config,
721
+ )
722
+
723
+ def patch(
724
+ self,
725
+ path: str,
726
+ data: Optional[Union[Dict[str, Any], str]] = None,
727
+ query: Optional[Dict[str, Any]] = None,
728
+ headers: Optional[Dict[str, str]] = None,
729
+ config: Optional[Config] = None,
730
+ ) -> Dict[str, Any]:
731
+ """
732
+ Make an async PATCH request.
733
+
734
+ Args:
735
+ path: API path (may include query string)
736
+ data: Request body
737
+ query: Query parameters to add/merge
738
+ headers: Additional headers
739
+
740
+ Returns:
741
+ Response body as dictionary
742
+
743
+ Raises:
744
+ AgentRunClientError: If the request fails
745
+ """
746
+ return self._make_request(
747
+ "PATCH",
748
+ self.with_path(path, query=query),
749
+ data=data,
750
+ headers=headers,
751
+ config=config,
752
+ )
753
+
754
+ async def delete_async(
755
+ self,
756
+ path: str,
757
+ query: Optional[Dict[str, Any]] = None,
758
+ headers: Optional[Dict[str, str]] = None,
759
+ config: Optional[Config] = None,
760
+ ) -> Dict[str, Any]:
761
+ """
762
+ Make an async DELETE request.
763
+
764
+ Args:
765
+ path: API path (may include query string)
766
+ query: Query parameters to add/merge
767
+ headers: Additional headers
768
+
769
+ Returns:
770
+ Response body as dictionary
771
+
772
+ Raises:
773
+ AgentRunClientError: If the request fails
774
+ """
775
+ return await self._make_request_async(
776
+ "DELETE",
777
+ self.with_path(path, query=query),
778
+ headers=headers,
779
+ config=config,
780
+ )
781
+
782
+ def delete(
783
+ self,
784
+ path: str,
785
+ query: Optional[Dict[str, Any]] = None,
786
+ headers: Optional[Dict[str, str]] = None,
787
+ config: Optional[Config] = None,
788
+ ) -> Dict[str, Any]:
789
+ """
790
+ Make an async DELETE request.
791
+
792
+ Args:
793
+ path: API path (may include query string)
794
+ query: Query parameters to add/merge
795
+ headers: Additional headers
796
+
797
+ Returns:
798
+ Response body as dictionary
799
+
800
+ Raises:
801
+ AgentRunClientError: If the request fails
802
+ """
803
+ return self._make_request(
804
+ "DELETE",
805
+ self.with_path(path, query=query),
806
+ headers=headers,
807
+ config=config,
808
+ )
809
+
810
+ async def post_file_async(
811
+ self,
812
+ path: str,
813
+ local_file_path: str,
814
+ target_file_path: str,
815
+ form_data: Optional[Dict[str, Any]] = None,
816
+ query: Optional[Dict[str, Any]] = None,
817
+ headers: Optional[Dict[str, str]] = None,
818
+ config: Optional[Config] = None,
819
+ ) -> Dict[str, Any]:
820
+ """
821
+ Asynchronously upload a file using multipart/form-data (POST request).
822
+
823
+ Args:
824
+ path: API path (may include query string)
825
+ local_file_path: Local file path to upload
826
+ target_file_path: Target file path on the server
827
+ form_data: Additional form data fields
828
+ query: Query parameters to add/merge
829
+ headers: Additional headers
830
+
831
+ Returns:
832
+ Response body as dictionary
833
+
834
+ Raises:
835
+ AgentRunClientError: If the request fails
836
+
837
+ Examples:
838
+ >>> await client.post_file_async("/files", local_file_path="/local/data.csv", target_file_path="/remote/data.csv")
839
+ >>> await client.post_file_async("/files", local_file_path="/local/data.csv", target_file_path="/remote/input.csv")
840
+ """
841
+ import os
842
+
843
+ filename = os.path.basename(local_file_path)
844
+
845
+ url = self.with_path(path, query=query)
846
+ req_headers = self.config.get_headers()
847
+ req_headers.update(headers or {})
848
+
849
+ try:
850
+ with open(local_file_path, "rb") as f:
851
+ file_content = f.read()
852
+ files = {"file": (filename, file_content)}
853
+ data = form_data or {}
854
+ data["path"] = target_file_path
855
+
856
+ async with httpx.AsyncClient(
857
+ timeout=self.config.get_timeout()
858
+ ) as client:
859
+ response = await client.post(
860
+ url, files=files, data=data, headers=req_headers
861
+ )
862
+ response.raise_for_status()
863
+ return response.json()
864
+ except httpx.HTTPStatusError as e:
865
+ raise ClientError(
866
+ status_code=e.response.status_code, message=e.response.text
867
+ ) from e
868
+
869
+ def post_file(
870
+ self,
871
+ path: str,
872
+ local_file_path: str,
873
+ target_file_path: str,
874
+ form_data: Optional[Dict[str, Any]] = None,
875
+ query: Optional[Dict[str, Any]] = None,
876
+ headers: Optional[Dict[str, str]] = None,
877
+ config: Optional[Config] = None,
878
+ ) -> Dict[str, Any]:
879
+ """
880
+ Synchronously upload a file using multipart/form-data (POST request).
881
+
882
+ Args:
883
+ path: API path (may include query string)
884
+ local_file_path: Local file path to upload
885
+ target_file_path: Target file path on the server
886
+ form_data: Additional form data fields
887
+ query: Query parameters to add/merge
888
+ headers: Additional headers
889
+
890
+ Returns:
891
+ Response body as dictionary
892
+
893
+ Raises:
894
+ AgentRunClientError: If the request fails
895
+
896
+ Examples:
897
+ >>> client.post_file("/files", local_file_path="/local/data.csv", target_file_path="/remote/data.csv")
898
+ >>> client.post_file("/files", local_file_path="/local/data.csv", target_file_path="/remote/input.csv")
899
+ """
900
+ import os
901
+
902
+ filename = os.path.basename(local_file_path)
903
+
904
+ url = self.with_path(path, query=query)
905
+ req_headers = self.config.get_headers()
906
+ req_headers.update(headers or {})
907
+
908
+ try:
909
+ with open(local_file_path, "rb") as f:
910
+ file_content = f.read()
911
+ files = {"file": (filename, file_content)}
912
+ data = form_data or {}
913
+ data["path"] = target_file_path
914
+
915
+ with httpx.Client(timeout=self.config.get_timeout()) as client:
916
+ response = client.post(
917
+ url, files=files, data=data, headers=req_headers
918
+ )
919
+ response.raise_for_status()
920
+ return response.json()
921
+ except httpx.HTTPStatusError as e:
922
+ raise ClientError(
923
+ status_code=e.response.status_code, message=e.response.text
924
+ ) from e
925
+
926
+ async def get_file_async(
927
+ self,
928
+ path: str,
929
+ save_path: str,
930
+ query: Optional[Dict[str, Any]] = None,
931
+ headers: Optional[Dict[str, str]] = None,
932
+ config: Optional[Config] = None,
933
+ ) -> Dict[str, Any]:
934
+ """
935
+ Asynchronously download a file and save it to local path (GET request).
936
+
937
+ Args:
938
+ path: API path (may include query string)
939
+ save_path: Local file path to save the downloaded file
940
+ query: Query parameters to add/merge
941
+ headers: Additional headers
942
+
943
+ Returns:
944
+ Dictionary with 'saved_path' and 'size' keys
945
+
946
+ Raises:
947
+ AgentRunClientError: If the request fails
948
+
949
+ Examples:
950
+ >>> await client.get_file_async("/files", save_path="/local/data.csv", query={"path": "/remote/file.csv"})
951
+ """
952
+ url = self.with_path(path, query=query)
953
+ req_headers = self.config.get_headers()
954
+ req_headers.update(headers or {})
955
+
956
+ try:
957
+ async with httpx.AsyncClient(
958
+ timeout=self.config.get_timeout()
959
+ ) as client:
960
+ response = await client.get(url, headers=req_headers)
961
+ response.raise_for_status()
962
+
963
+ with open(save_path, "wb") as f:
964
+ f.write(response.content)
965
+
966
+ return {"saved_path": save_path, "size": len(response.content)}
967
+ except httpx.HTTPStatusError as e:
968
+ raise ClientError(
969
+ status_code=e.response.status_code, message=e.response.text
970
+ ) from e
971
+
972
+ def get_file(
973
+ self,
974
+ path: str,
975
+ save_path: str,
976
+ query: Optional[Dict[str, Any]] = None,
977
+ headers: Optional[Dict[str, str]] = None,
978
+ config: Optional[Config] = None,
979
+ ) -> Dict[str, Any]:
980
+ """
981
+ Synchronously download a file and save it to local path (GET request).
982
+
983
+ Args:
984
+ path: API path (may include query string)
985
+ save_path: Local file path to save the downloaded file
986
+ query: Query parameters to add/merge
987
+ headers: Additional headers
988
+
989
+ Returns:
990
+ Dictionary with 'saved_path' and 'size' keys
991
+
992
+ Raises:
993
+ AgentRunClientError: If the request fails
994
+
995
+ Examples:
996
+ >>> client.get_file("/files", save_path="/local/data.csv", query={"path": "/remote/file.csv"})
997
+ """
998
+ url = self.with_path(path, query=query)
999
+ req_headers = self.config.get_headers()
1000
+ req_headers.update(headers or {})
1001
+
1002
+ try:
1003
+ with httpx.Client(timeout=self.config.get_timeout()) as client:
1004
+ response = client.get(url, headers=req_headers)
1005
+ response.raise_for_status()
1006
+
1007
+ with open(save_path, "wb") as f:
1008
+ f.write(response.content)
1009
+
1010
+ return {"saved_path": save_path, "size": len(response.content)}
1011
+ except httpx.HTTPStatusError as e:
1012
+ raise ClientError(
1013
+ status_code=e.response.status_code, message=e.response.text
1014
+ ) from e
1015
+
1016
+ async def get_video_async(
1017
+ self,
1018
+ path: str,
1019
+ save_path: str,
1020
+ query: Optional[Dict[str, Any]] = None,
1021
+ headers: Optional[Dict[str, str]] = None,
1022
+ config: Optional[Config] = None,
1023
+ ) -> Dict[str, Any]:
1024
+ """
1025
+ Asynchronously download a video file and save it to local path (GET request).
1026
+
1027
+ Args:
1028
+ path: API path (may include query string)
1029
+ save_path: Local file path to save the downloaded video file (.mkv)
1030
+ query: Query parameters to add/merge
1031
+ headers: Additional headers
1032
+
1033
+ Returns:
1034
+ Dictionary with 'saved_path' and 'size' keys
1035
+
1036
+ Raises:
1037
+ AgentRunClientError: If the request fails
1038
+
1039
+ Examples:
1040
+ >>> await client.get_video_async("/videos", save_path="/local/video.mkv", query={"path": "/remote/video.mp4"})
1041
+ """
1042
+ url = self.with_path(path, query=query)
1043
+ req_headers = self.config.get_headers()
1044
+ req_headers.update(headers or {})
1045
+ # Apply authentication (may modify URL, headers, and query)
1046
+ cfg = Config.with_configs(self.config, config)
1047
+ url, req_headers, query = self.auth(url, req_headers, query, config=cfg)
1048
+
1049
+ try:
1050
+ async with httpx.AsyncClient(
1051
+ timeout=self.config.get_timeout()
1052
+ ) as client:
1053
+ response = await client.get(url, headers=req_headers)
1054
+ response.raise_for_status()
1055
+
1056
+ with open(save_path, "wb") as f:
1057
+ f.write(response.content)
1058
+
1059
+ return {"saved_path": save_path, "size": len(response.content)}
1060
+ except httpx.HTTPStatusError as e:
1061
+ raise ClientError(
1062
+ status_code=e.response.status_code, message=e.response.text
1063
+ ) from e
1064
+
1065
+ def get_video(
1066
+ self,
1067
+ path: str,
1068
+ save_path: str,
1069
+ query: Optional[Dict[str, Any]] = None,
1070
+ headers: Optional[Dict[str, str]] = None,
1071
+ config: Optional[Config] = None,
1072
+ ) -> Dict[str, Any]:
1073
+ """
1074
+ Synchronously download a video file and save it to local path (GET request).
1075
+
1076
+ Args:
1077
+ path: API path (may include query string)
1078
+ save_path: Local file path to save the downloaded video file (.mkv)
1079
+ query: Query parameters to add/merge
1080
+ headers: Additional headers
1081
+
1082
+ Returns:
1083
+ Dictionary with 'saved_path' and 'size' keys
1084
+
1085
+ Raises:
1086
+ AgentRunClientError: If the request fails
1087
+
1088
+ Examples:
1089
+ >>> client.get_video("/videos", save_path="/local/video.mkv", query={"path": "/remote/video.mp4"})
1090
+ """
1091
+ url = self.with_path(path, query=query)
1092
+ req_headers = self.config.get_headers()
1093
+ req_headers.update(headers or {})
1094
+ # Apply authentication (may modify URL, headers, and query)
1095
+ cfg = Config.with_configs(self.config, config)
1096
+ url, req_headers, query = self.auth(url, req_headers, query, config=cfg)
1097
+
1098
+ try:
1099
+ with httpx.Client(timeout=self.config.get_timeout()) as client:
1100
+ response = client.get(url, headers=req_headers)
1101
+ response.raise_for_status()
1102
+
1103
+ with open(save_path, "wb") as f:
1104
+ f.write(response.content)
1105
+
1106
+ return {"saved_path": save_path, "size": len(response.content)}
1107
+ except httpx.HTTPStatusError as e:
1108
+ raise ClientError(
1109
+ status_code=e.response.status_code, message=e.response.text
1110
+ ) from e