agentrun-inner-test 0.0.62__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.

Potentially problematic release.


This version of agentrun-inner-test might be problematic. Click here for more details.

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