You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,8 +5,16 @@ existing `0.1.0` release; earlier development prereleases are not listed.
5
5
6
6
## [Unreleased]
7
7
8
+
### Added
9
+
10
+
- Export `RequestTooLargeError` for HTTP 413 and `OverloadedError` for HTTP 529 from `qca` and `qca.common`, matching Anthropic's Python SDK.
11
+
- Add `_strict_response_validation=True` to all four clients to require Pydantic validation of responses, including pagination and SSE. The setting is retained by `with_options` and response views.
12
+
8
13
### Changed
9
14
15
+
-**Breaking:** Responses now use lenient model construction by default, matching Anthropic's Python SDK. Unexpected field types are preserved instead of raising `APIResponseValidationError`; nested models, extra fields, and request IDs remain available. Enable `_strict_response_validation=True` to retain the previous schema validation behavior. Invalid JSON and invalid download URLs still raise in either mode.
16
+
-**Breaking:** HTTP 529 now raises `OverloadedError`, which inherits directly from `APIStatusError`, rather than `InternalServerError`. Callers catching `InternalServerError` for overloads should also catch `OverloadedError` or use `APIStatusError`.
17
+
- Honor positive `Retry-After` and `Retry-After-Ms` delays above 60 seconds, capped at 4,294,967 seconds. Zero and negative delays use exponential backoff; numeric millisecond headers take precedence. Retry eligibility is unchanged.
10
18
- Forward and Managed clients, both synchronous and asynchronous, now default to a 5-second connection timeout and 600-second read, write, and connection-pool timeouts, matching Anthropic's Python SDK. SSE streams can continue beyond 10 minutes while data keeps arriving within the read timeout.
Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+10Lines changed: 10 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,16 @@ The default test command excludes account-backed integration tests and must not
34
34
35
35
Never commit `.env.live`, tokens, credentials, generated logs, or test output. Integration scenarios must register cleanup immediately after creating a resource. Run them explicitly with `QODER_RUN_LIVE=1`; they are not part of public pull-request CI.
36
36
37
+
The Forward and Managed integration files also include six `strict_response_contract` checks using a separate client with `_strict_response_validation=True`: model, template/agent, and session lists. They send only GET requests, inspect the first page with `limit=1` where supported, and allow empty lists. An empty list checks the response envelope; item schemas are checked when items exist. Returned items must have a non-empty string ID, and `data` must be present even when empty. Existing business scenarios continue to use the default lenient response parsing.
These checks are included in the existing `test-live`, `test-live-managed`, and `test-live-all` targets. Offline regression tests use the same strict-client fixture and assertions with a mock HTTP transport to verify schema failures without credentials or network access.
Copy file name to clipboardExpand all lines: README.md
+20-2Lines changed: 20 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -203,7 +203,7 @@ Events are also readable after the fact through `client.sessions.events.list(ses
203
203
204
204
## Handling errors
205
205
206
-
`APIConnectionError` is raised when the request never reached the API; `APITimeoutError` is its timeout subclass. A non-2xx status raises an `APIStatusError` subclass, and a response that cannot be decoded into its declared type raises`APIResponseValidationError`. All of them derive from `qca.APIError`.
206
+
`APIConnectionError` is raised when the request never reached the API; `APITimeoutError` is its timeout subclass. A non-2xx status raises an `APIStatusError` subclass. Invalid JSON, invalid download URLs, and response schema mismatches when strict response validation is enabled raise`APIResponseValidationError`. All of them derive from `qca.APIError`.
207
207
208
208
```python
209
209
from qca import APIConnectionError, APIStatusError, APITimeoutError
@@ -225,13 +225,29 @@ except APIStatusError as exc:
225
225
| 403 |`PermissionDeniedError`|
226
226
| 404 |`NotFoundError`|
227
227
| 409 |`ConflictError`|
228
+
| 413 |`RequestTooLargeError`|
228
229
| 422 |`UnprocessableEntityError`|
229
230
| 429 |`RateLimitError`|
230
-
| 5xx |`InternalServerError`|
231
+
| 529 |`OverloadedError`|
232
+
| other 5xx |`InternalServerError`|
231
233
| other |`APIStatusError`|
232
234
233
235
`code` and `type` are read from the error body and are `None` when the server omits them, so log `message` and `request_id` as well. A non-JSON error body is kept verbatim in `.body`.
234
236
237
+
`RequestTooLargeError` and `OverloadedError` inherit directly from `APIStatusError`, matching Anthropic. Code that previously caught `InternalServerError` for status 529 should now catch `OverloadedError` as well, or catch `APIStatusError` for all HTTP errors.
238
+
239
+
## Response validation
240
+
241
+
By default, responses are constructed into models without requiring every field to match the declared schema, matching Anthropic's Python SDK. Nested objects are still converted to models and unknown fields are retained. Unexpected field values may keep their original type, so type annotations describe the expected API schema rather than guaranteeing the runtime value.
242
+
243
+
To require Pydantic response validation and raise `APIResponseValidationError` on a schema mismatch, enable the constructor option:
The option is available on `Forward`, `Managed`, `AsyncForward`, and `AsyncManaged`, and is preserved by `with_options`, raw and streaming response views, pagination, and SSE parsing. Invalid JSON and invalid download URLs still raise `APIResponseValidationError` in either mode. Direct construction or validation of model classes continues to use Pydantic validation.
250
+
235
251
## Request IDs
236
252
237
253
Every response model carries the `x-request-id` of the call that produced it, and errors expose the same value. Include it when reporting a problem.
@@ -245,6 +261,8 @@ print(identity._request_id)
245
261
246
262
Certain errors are retried twice by default with exponential backoff. GET and HEAD requests, and any request carrying an idempotency key, are retried on connection errors, 408, 429, and 5xx; other requests are retried on 429 only. A 409 is never retried automatically, and an SSE stream that has already been established is never retried. Within those rules the SDK honors `x-should-retry` and a valid `Retry-After-Ms` or `Retry-After`.
247
263
264
+
Positive server-requested delays, including values over 60 seconds, are honored up to 4,294,967 seconds, matching Anthropic's Python SDK. A numeric `Retry-After-Ms` takes precedence over `Retry-After`, which accepts seconds or an HTTP date. Zero, negative, or invalid delays fall back to exponential backoff. A server-requested wait can therefore exceed the timeout configured for an individual HTTP attempt.
265
+
248
266
```python
249
267
client = Forward(max_retries=0) # disable for all requests
250
268
client.with_options(max_retries=5).sessions.list() # or override per call site
0 commit comments