cloudsway-agent 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_api/__init__.py +68 -0
- agent_api/_http.py +392 -0
- agent_api/_utils.py +32 -0
- agent_api/_version.py +8 -0
- agent_api/async_client.py +57 -0
- agent_api/client.py +58 -0
- agent_api/errors.py +167 -0
- agent_api/local_functions.py +41 -0
- agent_api/pagination.py +77 -0
- agent_api/py.typed +1 -0
- agent_api/resources/catalog.py +51 -0
- agent_api/resources/responses.py +117 -0
- agent_api/streaming.py +43 -0
- agent_api/types/__init__.py +5 -0
- agent_api/types/common.py +34 -0
- agent_api/types/input.py +86 -0
- agent_api/types/responses.py +114 -0
- agent_api/types/streaming.py +70 -0
- agent_api/types/tools.py +39 -0
- cloudsway_agent-1.0.0.dist-info/METADATA +139 -0
- cloudsway_agent-1.0.0.dist-info/RECORD +24 -0
- cloudsway_agent-1.0.0.dist-info/WHEEL +5 -0
- cloudsway_agent-1.0.0.dist-info/licenses/LICENSE +21 -0
- cloudsway_agent-1.0.0.dist-info/top_level.txt +1 -0
agent_api/__init__.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Production Python SDK for the Managed Agent API."""
|
|
2
|
+
|
|
3
|
+
from agent_api._version import (
|
|
4
|
+
DEFAULT_MAX_RETRIES,
|
|
5
|
+
DEFAULT_STREAM_TIMEOUT,
|
|
6
|
+
DEFAULT_TIMEOUT,
|
|
7
|
+
USER_AGENT,
|
|
8
|
+
__version__,
|
|
9
|
+
)
|
|
10
|
+
from agent_api.async_client import AsyncAgentAPI
|
|
11
|
+
from agent_api.client import AgentAPI
|
|
12
|
+
from agent_api.errors import (
|
|
13
|
+
APIConnectionError,
|
|
14
|
+
APIError,
|
|
15
|
+
APIStatusError,
|
|
16
|
+
AuthenticationError,
|
|
17
|
+
BadRequestError,
|
|
18
|
+
InternalServerError,
|
|
19
|
+
NotFoundError,
|
|
20
|
+
PermissionDeniedError,
|
|
21
|
+
RateLimitError,
|
|
22
|
+
is_retryable_status,
|
|
23
|
+
parse_response_error,
|
|
24
|
+
)
|
|
25
|
+
from agent_api.local_functions import (
|
|
26
|
+
function_call_output_input,
|
|
27
|
+
pending_function_calls,
|
|
28
|
+
run_local_function_handlers,
|
|
29
|
+
)
|
|
30
|
+
from agent_api.pagination import AsyncPage, Page, PageResult
|
|
31
|
+
from agent_api.types import *
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"AgentAPI",
|
|
35
|
+
"AsyncAgentAPI",
|
|
36
|
+
"APIError",
|
|
37
|
+
"APIConnectionError",
|
|
38
|
+
"APIStatusError",
|
|
39
|
+
"AuthenticationError",
|
|
40
|
+
"BadRequestError",
|
|
41
|
+
"InternalServerError",
|
|
42
|
+
"NotFoundError",
|
|
43
|
+
"PermissionDeniedError",
|
|
44
|
+
"RateLimitError",
|
|
45
|
+
"Page",
|
|
46
|
+
"AsyncPage",
|
|
47
|
+
"PageResult",
|
|
48
|
+
"AgentCapabilityPreference",
|
|
49
|
+
"AgentResponse",
|
|
50
|
+
"Model",
|
|
51
|
+
"ModelCapabilities",
|
|
52
|
+
"Preset",
|
|
53
|
+
"PublicTool",
|
|
54
|
+
"ResponseCreateParams",
|
|
55
|
+
"ResponseStreamEvent",
|
|
56
|
+
"ResponseStatus",
|
|
57
|
+
"ToolInvocationResult",
|
|
58
|
+
"DEFAULT_MAX_RETRIES",
|
|
59
|
+
"DEFAULT_STREAM_TIMEOUT",
|
|
60
|
+
"DEFAULT_TIMEOUT",
|
|
61
|
+
"USER_AGENT",
|
|
62
|
+
"is_retryable_status",
|
|
63
|
+
"parse_response_error",
|
|
64
|
+
"function_call_output_input",
|
|
65
|
+
"pending_function_calls",
|
|
66
|
+
"run_local_function_handlers",
|
|
67
|
+
"__version__",
|
|
68
|
+
]
|
agent_api/_http.py
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
import time
|
|
5
|
+
from collections.abc import AsyncIterator, Iterator, Mapping
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
from agent_api._utils import build_query
|
|
11
|
+
from agent_api._version import DEFAULT_MAX_RETRIES, DEFAULT_STREAM_TIMEOUT, DEFAULT_TIMEOUT, USER_AGENT
|
|
12
|
+
from agent_api.errors import (
|
|
13
|
+
APIConnectionError,
|
|
14
|
+
APIError,
|
|
15
|
+
APIStatusError,
|
|
16
|
+
RateLimitError,
|
|
17
|
+
is_retryable_status,
|
|
18
|
+
parse_response_error,
|
|
19
|
+
)
|
|
20
|
+
from agent_api.streaming import aiter_sse, iter_sse
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SyncHTTPClient:
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
*,
|
|
27
|
+
base_url: str,
|
|
28
|
+
api_key: str | None,
|
|
29
|
+
timeout: float,
|
|
30
|
+
stream_timeout: float,
|
|
31
|
+
max_retries: int,
|
|
32
|
+
default_headers: Mapping[str, str],
|
|
33
|
+
http_client: httpx.Client,
|
|
34
|
+
) -> None:
|
|
35
|
+
self.base_url = base_url
|
|
36
|
+
self.api_key = api_key
|
|
37
|
+
self.timeout = timeout
|
|
38
|
+
self.stream_timeout = stream_timeout
|
|
39
|
+
self.max_retries = max_retries
|
|
40
|
+
self.default_headers = dict(default_headers)
|
|
41
|
+
self._client = http_client
|
|
42
|
+
|
|
43
|
+
def request(
|
|
44
|
+
self,
|
|
45
|
+
method: str,
|
|
46
|
+
path: str,
|
|
47
|
+
body: dict[str, Any] | None,
|
|
48
|
+
*,
|
|
49
|
+
timeout: float | None = None,
|
|
50
|
+
max_retries: int | None = None,
|
|
51
|
+
extra_headers: Mapping[str, str] | None = None,
|
|
52
|
+
) -> Any:
|
|
53
|
+
response = self._request_response(
|
|
54
|
+
method,
|
|
55
|
+
path,
|
|
56
|
+
body,
|
|
57
|
+
stream=False,
|
|
58
|
+
timeout=timeout,
|
|
59
|
+
max_retries=max_retries,
|
|
60
|
+
extra_headers=extra_headers,
|
|
61
|
+
)
|
|
62
|
+
return response.json()
|
|
63
|
+
|
|
64
|
+
def stream(
|
|
65
|
+
self,
|
|
66
|
+
method: str,
|
|
67
|
+
path: str,
|
|
68
|
+
body: dict[str, Any],
|
|
69
|
+
*,
|
|
70
|
+
timeout: float | None = None,
|
|
71
|
+
max_retries: int | None = None,
|
|
72
|
+
extra_headers: Mapping[str, str] | None = None,
|
|
73
|
+
) -> Iterator[Any]:
|
|
74
|
+
effective_timeout = timeout if timeout is not None else self.stream_timeout
|
|
75
|
+
headers = self._headers(stream=True, extra=extra_headers)
|
|
76
|
+
retries = self.max_retries if max_retries is None else max_retries
|
|
77
|
+
attempt = 0
|
|
78
|
+
while True:
|
|
79
|
+
try:
|
|
80
|
+
with self._client.stream(
|
|
81
|
+
method,
|
|
82
|
+
self.base_url + path,
|
|
83
|
+
json=body,
|
|
84
|
+
headers=headers,
|
|
85
|
+
timeout=effective_timeout,
|
|
86
|
+
) as response:
|
|
87
|
+
if not response.is_success:
|
|
88
|
+
try:
|
|
89
|
+
payload: Any = response.json()
|
|
90
|
+
except ValueError:
|
|
91
|
+
payload = response.text
|
|
92
|
+
raise parse_response_error(response, payload)
|
|
93
|
+
yield from iter_sse(response.iter_lines())
|
|
94
|
+
return
|
|
95
|
+
except APIError as exc:
|
|
96
|
+
if attempt >= retries:
|
|
97
|
+
raise
|
|
98
|
+
retryable = isinstance(exc, APIConnectionError) or (
|
|
99
|
+
isinstance(exc, APIStatusError) and exc.status_code is not None and is_retryable_status(exc.status_code)
|
|
100
|
+
)
|
|
101
|
+
if not retryable:
|
|
102
|
+
raise
|
|
103
|
+
attempt += 1
|
|
104
|
+
time.sleep(_retry_delay_seconds(exc, attempt))
|
|
105
|
+
except httpx.TimeoutException as exc:
|
|
106
|
+
raise APIConnectionError(f"Request timed out after {effective_timeout}s") from exc
|
|
107
|
+
except httpx.HTTPError as exc:
|
|
108
|
+
raise APIConnectionError(str(exc)) from exc
|
|
109
|
+
|
|
110
|
+
def _request_response(
|
|
111
|
+
self,
|
|
112
|
+
method: str,
|
|
113
|
+
path: str,
|
|
114
|
+
body: dict[str, Any] | None,
|
|
115
|
+
*,
|
|
116
|
+
stream: bool,
|
|
117
|
+
timeout: float | None,
|
|
118
|
+
max_retries: int | None,
|
|
119
|
+
extra_headers: Mapping[str, str] | None,
|
|
120
|
+
) -> httpx.Response:
|
|
121
|
+
retries = self.max_retries if max_retries is None else max_retries
|
|
122
|
+
attempt = 0
|
|
123
|
+
while True:
|
|
124
|
+
try:
|
|
125
|
+
return self._request_once(
|
|
126
|
+
method,
|
|
127
|
+
path,
|
|
128
|
+
body,
|
|
129
|
+
stream=stream,
|
|
130
|
+
timeout=timeout,
|
|
131
|
+
extra_headers=extra_headers,
|
|
132
|
+
)
|
|
133
|
+
except APIError as exc:
|
|
134
|
+
if attempt >= retries:
|
|
135
|
+
raise
|
|
136
|
+
retryable = isinstance(exc, APIConnectionError) or (
|
|
137
|
+
isinstance(exc, APIStatusError) and exc.status_code is not None and is_retryable_status(exc.status_code)
|
|
138
|
+
)
|
|
139
|
+
if not retryable:
|
|
140
|
+
raise
|
|
141
|
+
attempt += 1
|
|
142
|
+
time.sleep(_retry_delay_seconds(exc, attempt))
|
|
143
|
+
|
|
144
|
+
def _request_once(
|
|
145
|
+
self,
|
|
146
|
+
method: str,
|
|
147
|
+
path: str,
|
|
148
|
+
body: dict[str, Any] | None,
|
|
149
|
+
*,
|
|
150
|
+
stream: bool,
|
|
151
|
+
timeout: float | None,
|
|
152
|
+
extra_headers: Mapping[str, str] | None,
|
|
153
|
+
) -> httpx.Response:
|
|
154
|
+
effective_timeout = timeout if timeout is not None else (self.stream_timeout if stream else self.timeout)
|
|
155
|
+
headers = self._headers(stream=stream, extra=extra_headers)
|
|
156
|
+
try:
|
|
157
|
+
if stream:
|
|
158
|
+
request = self._client.build_request(
|
|
159
|
+
method,
|
|
160
|
+
self.base_url + path,
|
|
161
|
+
json=body,
|
|
162
|
+
headers=headers,
|
|
163
|
+
timeout=effective_timeout,
|
|
164
|
+
)
|
|
165
|
+
response = self._client.send(request, stream=True)
|
|
166
|
+
else:
|
|
167
|
+
response = self._client.request(
|
|
168
|
+
method,
|
|
169
|
+
self.base_url + path,
|
|
170
|
+
json=body,
|
|
171
|
+
headers=headers,
|
|
172
|
+
timeout=effective_timeout,
|
|
173
|
+
)
|
|
174
|
+
except httpx.TimeoutException as exc:
|
|
175
|
+
raise APIConnectionError(f"Request timed out after {effective_timeout}s") from exc
|
|
176
|
+
except httpx.HTTPError as exc:
|
|
177
|
+
raise APIConnectionError(str(exc)) from exc
|
|
178
|
+
|
|
179
|
+
if response.is_success:
|
|
180
|
+
return response
|
|
181
|
+
try:
|
|
182
|
+
payload: Any = response.json()
|
|
183
|
+
except ValueError:
|
|
184
|
+
payload = response.text
|
|
185
|
+
raise parse_response_error(response, payload)
|
|
186
|
+
|
|
187
|
+
def _headers(self, *, stream: bool, extra: Mapping[str, str] | None) -> dict[str, str]:
|
|
188
|
+
headers = {
|
|
189
|
+
"Accept": "text/event-stream" if stream else "application/json",
|
|
190
|
+
"User-Agent": USER_AGENT,
|
|
191
|
+
**self.default_headers,
|
|
192
|
+
**dict(extra or {}),
|
|
193
|
+
}
|
|
194
|
+
if self.api_key:
|
|
195
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
196
|
+
return headers
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class AsyncHTTPClient:
|
|
200
|
+
def __init__(
|
|
201
|
+
self,
|
|
202
|
+
*,
|
|
203
|
+
base_url: str,
|
|
204
|
+
api_key: str | None,
|
|
205
|
+
timeout: float,
|
|
206
|
+
stream_timeout: float,
|
|
207
|
+
max_retries: int,
|
|
208
|
+
default_headers: Mapping[str, str],
|
|
209
|
+
http_client: httpx.AsyncClient,
|
|
210
|
+
) -> None:
|
|
211
|
+
self.base_url = base_url
|
|
212
|
+
self.api_key = api_key
|
|
213
|
+
self.timeout = timeout
|
|
214
|
+
self.stream_timeout = stream_timeout
|
|
215
|
+
self.max_retries = max_retries
|
|
216
|
+
self.default_headers = dict(default_headers)
|
|
217
|
+
self._client = http_client
|
|
218
|
+
|
|
219
|
+
async def request(
|
|
220
|
+
self,
|
|
221
|
+
method: str,
|
|
222
|
+
path: str,
|
|
223
|
+
body: dict[str, Any] | None,
|
|
224
|
+
*,
|
|
225
|
+
timeout: float | None = None,
|
|
226
|
+
max_retries: int | None = None,
|
|
227
|
+
extra_headers: Mapping[str, str] | None = None,
|
|
228
|
+
) -> Any:
|
|
229
|
+
response = await self._request_response(
|
|
230
|
+
method,
|
|
231
|
+
path,
|
|
232
|
+
body,
|
|
233
|
+
stream=False,
|
|
234
|
+
timeout=timeout,
|
|
235
|
+
max_retries=max_retries,
|
|
236
|
+
extra_headers=extra_headers,
|
|
237
|
+
)
|
|
238
|
+
return response.json()
|
|
239
|
+
|
|
240
|
+
async def stream(
|
|
241
|
+
self,
|
|
242
|
+
method: str,
|
|
243
|
+
path: str,
|
|
244
|
+
body: dict[str, Any],
|
|
245
|
+
*,
|
|
246
|
+
timeout: float | None = None,
|
|
247
|
+
max_retries: int | None = None,
|
|
248
|
+
extra_headers: Mapping[str, str] | None = None,
|
|
249
|
+
) -> AsyncIterator[Any]:
|
|
250
|
+
effective_timeout = timeout if timeout is not None else self.stream_timeout
|
|
251
|
+
headers = self._headers(stream=True, extra=extra_headers)
|
|
252
|
+
retries = self.max_retries if max_retries is None else max_retries
|
|
253
|
+
attempt = 0
|
|
254
|
+
while True:
|
|
255
|
+
try:
|
|
256
|
+
async with self._client.stream(
|
|
257
|
+
method,
|
|
258
|
+
self.base_url + path,
|
|
259
|
+
json=body,
|
|
260
|
+
headers=headers,
|
|
261
|
+
timeout=effective_timeout,
|
|
262
|
+
) as response:
|
|
263
|
+
if not response.is_success:
|
|
264
|
+
try:
|
|
265
|
+
payload: Any = response.json()
|
|
266
|
+
except ValueError:
|
|
267
|
+
payload = response.text
|
|
268
|
+
raise parse_response_error(response, payload)
|
|
269
|
+
async for event in aiter_sse(response.aiter_lines()):
|
|
270
|
+
yield event
|
|
271
|
+
return
|
|
272
|
+
except APIError as exc:
|
|
273
|
+
if attempt >= retries:
|
|
274
|
+
raise
|
|
275
|
+
retryable = isinstance(exc, APIConnectionError) or (
|
|
276
|
+
isinstance(exc, APIStatusError) and exc.status_code is not None and is_retryable_status(exc.status_code)
|
|
277
|
+
)
|
|
278
|
+
if not retryable:
|
|
279
|
+
raise
|
|
280
|
+
attempt += 1
|
|
281
|
+
await _async_sleep(_retry_delay_seconds(exc, attempt))
|
|
282
|
+
except httpx.TimeoutException as exc:
|
|
283
|
+
raise APIConnectionError(f"Request timed out after {effective_timeout}s") from exc
|
|
284
|
+
except httpx.HTTPError as exc:
|
|
285
|
+
raise APIConnectionError(str(exc)) from exc
|
|
286
|
+
|
|
287
|
+
async def _request_response(
|
|
288
|
+
self,
|
|
289
|
+
method: str,
|
|
290
|
+
path: str,
|
|
291
|
+
body: dict[str, Any] | None,
|
|
292
|
+
*,
|
|
293
|
+
stream: bool,
|
|
294
|
+
timeout: float | None,
|
|
295
|
+
max_retries: int | None,
|
|
296
|
+
extra_headers: Mapping[str, str] | None,
|
|
297
|
+
) -> httpx.Response:
|
|
298
|
+
retries = self.max_retries if max_retries is None else max_retries
|
|
299
|
+
attempt = 0
|
|
300
|
+
while True:
|
|
301
|
+
try:
|
|
302
|
+
return await self._request_once(
|
|
303
|
+
method,
|
|
304
|
+
path,
|
|
305
|
+
body,
|
|
306
|
+
stream=stream,
|
|
307
|
+
timeout=timeout,
|
|
308
|
+
extra_headers=extra_headers,
|
|
309
|
+
)
|
|
310
|
+
except APIError as exc:
|
|
311
|
+
if attempt >= retries:
|
|
312
|
+
raise
|
|
313
|
+
retryable = isinstance(exc, APIConnectionError) or (
|
|
314
|
+
isinstance(exc, APIStatusError) and exc.status_code is not None and is_retryable_status(exc.status_code)
|
|
315
|
+
)
|
|
316
|
+
if not retryable:
|
|
317
|
+
raise
|
|
318
|
+
attempt += 1
|
|
319
|
+
await _async_sleep(_retry_delay_seconds(exc, attempt))
|
|
320
|
+
|
|
321
|
+
async def _request_once(
|
|
322
|
+
self,
|
|
323
|
+
method: str,
|
|
324
|
+
path: str,
|
|
325
|
+
body: dict[str, Any] | None,
|
|
326
|
+
*,
|
|
327
|
+
stream: bool,
|
|
328
|
+
timeout: float | None,
|
|
329
|
+
extra_headers: Mapping[str, str] | None,
|
|
330
|
+
) -> httpx.Response:
|
|
331
|
+
effective_timeout = timeout if timeout is not None else (self.stream_timeout if stream else self.timeout)
|
|
332
|
+
headers = self._headers(stream=stream, extra=extra_headers)
|
|
333
|
+
try:
|
|
334
|
+
if stream:
|
|
335
|
+
request = self._client.build_request(
|
|
336
|
+
method,
|
|
337
|
+
self.base_url + path,
|
|
338
|
+
json=body,
|
|
339
|
+
headers=headers,
|
|
340
|
+
timeout=effective_timeout,
|
|
341
|
+
)
|
|
342
|
+
response = await self._client.send(request, stream=True)
|
|
343
|
+
else:
|
|
344
|
+
response = await self._client.request(
|
|
345
|
+
method,
|
|
346
|
+
self.base_url + path,
|
|
347
|
+
json=body,
|
|
348
|
+
headers=headers,
|
|
349
|
+
timeout=effective_timeout,
|
|
350
|
+
)
|
|
351
|
+
except httpx.TimeoutException as exc:
|
|
352
|
+
raise APIConnectionError(f"Request timed out after {effective_timeout}s") from exc
|
|
353
|
+
except httpx.HTTPError as exc:
|
|
354
|
+
raise APIConnectionError(str(exc)) from exc
|
|
355
|
+
|
|
356
|
+
if response.is_success:
|
|
357
|
+
return response
|
|
358
|
+
try:
|
|
359
|
+
payload: Any = response.json()
|
|
360
|
+
except ValueError:
|
|
361
|
+
payload = response.text
|
|
362
|
+
raise parse_response_error(response, payload)
|
|
363
|
+
|
|
364
|
+
def _headers(self, *, stream: bool, extra: Mapping[str, str] | None) -> dict[str, str]:
|
|
365
|
+
headers = {
|
|
366
|
+
"Accept": "text/event-stream" if stream else "application/json",
|
|
367
|
+
"User-Agent": USER_AGENT,
|
|
368
|
+
**self.default_headers,
|
|
369
|
+
**dict(extra or {}),
|
|
370
|
+
}
|
|
371
|
+
if self.api_key:
|
|
372
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
373
|
+
return headers
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _retry_delay_seconds(error: APIError, attempt: int) -> float:
|
|
377
|
+
if isinstance(error, RateLimitError) and error.retry_after_seconds is not None:
|
|
378
|
+
return error.retry_after_seconds
|
|
379
|
+
base = 0.25
|
|
380
|
+
cap = 8.0
|
|
381
|
+
exponential = min(cap, base * (2 ** (attempt - 1)))
|
|
382
|
+
jitter = random.uniform(0, 0.1)
|
|
383
|
+
return exponential + jitter
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
async def _async_sleep(seconds: float) -> None:
|
|
387
|
+
import asyncio
|
|
388
|
+
|
|
389
|
+
await asyncio.sleep(seconds)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
__all__ = ["SyncHTTPClient", "AsyncHTTPClient"]
|
agent_api/_utils.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from agent_api.types import AgentResponse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def drop_none(values: dict[str, Any]) -> dict[str, Any]:
|
|
9
|
+
return {key: value for key, value in values.items() if value is not None}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def add_output_text(response: AgentResponse) -> AgentResponse:
|
|
13
|
+
if "output_text" in response:
|
|
14
|
+
return response
|
|
15
|
+
text = ""
|
|
16
|
+
for item in response.get("output", []):
|
|
17
|
+
if item.get("type") != "message":
|
|
18
|
+
continue
|
|
19
|
+
for part in item.get("content", []):
|
|
20
|
+
if part.get("type") == "output_text":
|
|
21
|
+
text += part.get("text", "")
|
|
22
|
+
response["output_text"] = text
|
|
23
|
+
return response
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def build_query(params: dict[str, Any]) -> str:
|
|
27
|
+
filtered = {key: value for key, value in params.items() if value is not None and value != ""}
|
|
28
|
+
if not filtered:
|
|
29
|
+
return ""
|
|
30
|
+
from urllib.parse import urlencode
|
|
31
|
+
|
|
32
|
+
return "?" + urlencode(filtered)
|
agent_api/_version.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from agent_api._http import AsyncHTTPClient
|
|
9
|
+
from agent_api._version import DEFAULT_MAX_RETRIES, DEFAULT_STREAM_TIMEOUT, DEFAULT_TIMEOUT
|
|
10
|
+
from agent_api.resources.catalog import AsyncModelsAPI, AsyncPresetsAPI, AsyncToolsAPI
|
|
11
|
+
from agent_api.resources.responses import AsyncResponsesAPI
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AsyncAgentAPI:
|
|
15
|
+
"""Asynchronous production client for the Managed Agent API."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
*,
|
|
20
|
+
api_key: str | None = None,
|
|
21
|
+
base_url: str | None = None,
|
|
22
|
+
timeout: float | httpx.Timeout | None = None,
|
|
23
|
+
stream_timeout: float | None = None,
|
|
24
|
+
max_retries: int | None = None,
|
|
25
|
+
default_headers: Mapping[str, str] | None = None,
|
|
26
|
+
http_client: httpx.AsyncClient | None = None,
|
|
27
|
+
) -> None:
|
|
28
|
+
self.api_key = api_key or os.environ.get("AGENT_API_KEY")
|
|
29
|
+
self.base_url = (base_url or os.environ.get("AGENT_API_BASE_URL") or "https://api.agentsway.dev").rstrip("/")
|
|
30
|
+
self.timeout = float(timeout) if isinstance(timeout, (int, float)) else DEFAULT_TIMEOUT
|
|
31
|
+
self.stream_timeout = stream_timeout if stream_timeout is not None else DEFAULT_STREAM_TIMEOUT
|
|
32
|
+
self.max_retries = max_retries if max_retries is not None else DEFAULT_MAX_RETRIES
|
|
33
|
+
self.default_headers = dict(default_headers or {})
|
|
34
|
+
self._client = http_client or httpx.AsyncClient(timeout=timeout or DEFAULT_TIMEOUT)
|
|
35
|
+
self._http = AsyncHTTPClient(
|
|
36
|
+
base_url=self.base_url,
|
|
37
|
+
api_key=self.api_key,
|
|
38
|
+
timeout=self.timeout,
|
|
39
|
+
stream_timeout=self.stream_timeout,
|
|
40
|
+
max_retries=self.max_retries,
|
|
41
|
+
default_headers=self.default_headers,
|
|
42
|
+
http_client=self._client,
|
|
43
|
+
)
|
|
44
|
+
self.responses = AsyncResponsesAPI(self._http, "/v1/responses")
|
|
45
|
+
self.agent = AsyncResponsesAPI(self._http, "/v1/agent")
|
|
46
|
+
self.models = AsyncModelsAPI(self._http)
|
|
47
|
+
self.presets = AsyncPresetsAPI(self._http)
|
|
48
|
+
self.tools = AsyncToolsAPI(self._http)
|
|
49
|
+
|
|
50
|
+
async def close(self) -> None:
|
|
51
|
+
await self._client.aclose()
|
|
52
|
+
|
|
53
|
+
async def __aenter__(self) -> AsyncAgentAPI:
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
async def __aexit__(self, *_exc: object) -> None:
|
|
57
|
+
await self.close()
|
agent_api/client.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from agent_api._http import SyncHTTPClient
|
|
9
|
+
from agent_api._version import DEFAULT_MAX_RETRIES, DEFAULT_STREAM_TIMEOUT, DEFAULT_TIMEOUT
|
|
10
|
+
from agent_api.resources.catalog import ModelsAPI, PresetsAPI, ToolsAPI
|
|
11
|
+
from agent_api.resources.responses import ResponsesAPI
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AgentAPI:
|
|
15
|
+
"""Synchronous production client for the Managed Agent API."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
*,
|
|
20
|
+
api_key: str | None = None,
|
|
21
|
+
base_url: str | None = None,
|
|
22
|
+
timeout: float | httpx.Timeout | None = None,
|
|
23
|
+
stream_timeout: float | None = None,
|
|
24
|
+
max_retries: int | None = None,
|
|
25
|
+
default_headers: Mapping[str, str] | None = None,
|
|
26
|
+
http_client: httpx.Client | None = None,
|
|
27
|
+
) -> None:
|
|
28
|
+
self.api_key = api_key or os.environ.get("AGENT_API_KEY")
|
|
29
|
+
self.base_url = (base_url or os.environ.get("AGENT_API_BASE_URL") or "https://api.agentsway.dev").rstrip("/")
|
|
30
|
+
self.timeout = float(timeout) if isinstance(timeout, (int, float)) else DEFAULT_TIMEOUT
|
|
31
|
+
self.stream_timeout = stream_timeout if stream_timeout is not None else DEFAULT_STREAM_TIMEOUT
|
|
32
|
+
self.max_retries = max_retries if max_retries is not None else DEFAULT_MAX_RETRIES
|
|
33
|
+
self.default_headers = dict(default_headers or {})
|
|
34
|
+
self._client = http_client or httpx.Client(timeout=timeout or DEFAULT_TIMEOUT)
|
|
35
|
+
self._http = SyncHTTPClient(
|
|
36
|
+
base_url=self.base_url,
|
|
37
|
+
api_key=self.api_key,
|
|
38
|
+
timeout=self.timeout,
|
|
39
|
+
stream_timeout=self.stream_timeout,
|
|
40
|
+
max_retries=self.max_retries,
|
|
41
|
+
default_headers=self.default_headers,
|
|
42
|
+
http_client=self._client,
|
|
43
|
+
)
|
|
44
|
+
self.responses = ResponsesAPI(self._http, "/v1/responses")
|
|
45
|
+
self.agent = ResponsesAPI(self._http, "/v1/agent")
|
|
46
|
+
self.models = ModelsAPI(self._http)
|
|
47
|
+
self.presets = PresetsAPI(self._http)
|
|
48
|
+
self.tools = ToolsAPI(self._http)
|
|
49
|
+
|
|
50
|
+
def close(self) -> None:
|
|
51
|
+
self._client.close()
|
|
52
|
+
|
|
53
|
+
def __enter__(self) -> AgentAPI:
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def __exit__(self, *_exc: object) -> None:
|
|
57
|
+
self.close()
|
|
58
|
+
|