|
6 | 6 | (async) so the rest of the SDK can speak in plain Python data structures. |
7 | 7 | The transport layer is responsible for: |
8 | 8 |
|
9 | | -* injecting auth / workspace / uid / x-request-id headers, |
| 9 | +* injecting auth / workspace / uid headers, |
10 | 10 | * JSON encoding / decoding the request and response bodies, |
11 | 11 | * converting non-2xx responses into :class:`AgentStudioError`, |
12 | 12 | * retry-on-network-error with bounded exponential backoff. |
|
22 | 22 | import random |
23 | 23 | import socket |
24 | 24 | import time |
25 | | -import uuid |
26 | 25 | from dataclasses import dataclass |
27 | 26 | from typing import Any, Dict, IO, Mapping, Optional, Tuple, Union |
28 | 27 |
|
@@ -132,15 +131,6 @@ def is_error_payload(payload: Any) -> bool: |
132 | 131 | return False |
133 | 132 |
|
134 | 133 |
|
135 | | -def _new_request_id() -> str: |
136 | | - """Generate ``req_<26-char ULID-ish>``. |
137 | | -
|
138 | | - We use a UUID4 substring rather than an actual ULID to avoid an extra |
139 | | - runtime dependency – the backend treats this header opaquely. |
140 | | - """ |
141 | | - |
142 | | - return "req_" + uuid.uuid4().hex[:26] |
143 | | - |
144 | 134 |
|
145 | 135 | def _resolve_timeout( |
146 | 136 | timeout: Union[float, httpx.Timeout, Tuple[float, float], None], |
@@ -381,31 +371,31 @@ def request( # pylint: disable=too-many-branches |
381 | 371 | if attempt >= self.max_retries or not should_retry: |
382 | 372 | raise exceptions.APIConnectionError(str(exc)) from exc |
383 | 373 | else: |
384 | | - if not stream and _should_retry( |
385 | | - resp.status_code, |
386 | | - resp.headers, |
| 374 | + if stream: |
| 375 | + if resp.status_code >= 400: |
| 376 | + resp.read() |
| 377 | + else: |
| 378 | + return resp |
| 379 | + if _should_retry( |
| 380 | + resp.status_code, resp.headers, |
387 | 381 | ): |
388 | 382 | last_exc = exceptions.APIStatusError( |
389 | 383 | f"HTTP {resp.status_code}", |
390 | 384 | status_code=resp.status_code, |
391 | 385 | ) |
392 | | - if attempt >= self.max_retries: |
393 | | - try: |
394 | | - return self._parse(resp) |
395 | | - finally: |
396 | | - resp.close() |
397 | | - wait = _get_retry_after(resp.headers) or _backoff(attempt) |
398 | | - resp.close() |
399 | | - time.sleep(wait) |
400 | | - attempt += 1 |
401 | | - continue |
402 | | - if stream: |
403 | | - return resp |
| 386 | + if attempt < self.max_retries: |
| 387 | + wait = ( |
| 388 | + _get_retry_after(resp.headers) |
| 389 | + or _backoff(attempt) |
| 390 | + ) |
| 391 | + resp.close() |
| 392 | + time.sleep(wait) |
| 393 | + attempt += 1 |
| 394 | + continue |
404 | 395 | try: |
405 | 396 | return self._parse(resp) |
406 | 397 | finally: |
407 | | - if not stream: |
408 | | - resp.close() |
| 398 | + resp.close() |
409 | 399 | time.sleep(_backoff(attempt)) |
410 | 400 | attempt += 1 |
411 | 401 | raise exceptions.APIConnectionError( |
@@ -470,9 +460,9 @@ def __exit__( |
470 | 460 | self.close() |
471 | 461 |
|
472 | 462 | def __del__(self) -> None: |
473 | | - if self.is_closed: |
474 | | - return |
475 | 463 | try: |
| 464 | + if self.is_closed: |
| 465 | + return |
476 | 466 | self.close() |
477 | 467 | except Exception: |
478 | 468 | pass |
@@ -605,31 +595,31 @@ async def request( # pylint: disable=too-many-branches |
605 | 595 | if attempt >= self.max_retries or not should_retry: |
606 | 596 | raise exceptions.APIConnectionError(str(exc)) from exc |
607 | 597 | else: |
608 | | - if not stream and _should_retry( |
609 | | - resp.status_code, |
610 | | - resp.headers, |
| 598 | + if stream: |
| 599 | + if resp.status_code >= 400: |
| 600 | + await resp.aread() |
| 601 | + else: |
| 602 | + return resp |
| 603 | + if _should_retry( |
| 604 | + resp.status_code, resp.headers, |
611 | 605 | ): |
612 | 606 | last_exc = exceptions.APIStatusError( |
613 | 607 | f"HTTP {resp.status_code}", |
614 | 608 | status_code=resp.status_code, |
615 | 609 | ) |
616 | | - if attempt >= self.max_retries: |
617 | | - try: |
618 | | - return await self._parse(resp) |
619 | | - finally: |
620 | | - await resp.aclose() |
621 | | - wait = _get_retry_after(resp.headers) or _backoff(attempt) |
622 | | - await resp.aclose() |
623 | | - await asyncio.sleep(wait) |
624 | | - attempt += 1 |
625 | | - continue |
626 | | - if stream: |
627 | | - return resp |
| 610 | + if attempt < self.max_retries: |
| 611 | + wait = ( |
| 612 | + _get_retry_after(resp.headers) |
| 613 | + or _backoff(attempt) |
| 614 | + ) |
| 615 | + await resp.aclose() |
| 616 | + await asyncio.sleep(wait) |
| 617 | + attempt += 1 |
| 618 | + continue |
628 | 619 | try: |
629 | 620 | return await self._parse(resp) |
630 | 621 | finally: |
631 | | - if not stream: |
632 | | - await resp.aclose() |
| 622 | + await resp.aclose() |
633 | 623 | await asyncio.sleep(_backoff(attempt)) |
634 | 624 | attempt += 1 |
635 | 625 | raise exceptions.APIConnectionError( |
|
0 commit comments