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
Synchronous and natively asynchronous clients for Python 3.10+, with typed responses, automatic pagination, SSE streaming, and file transfer.
4
4
5
-
完整 API 参考:[Forward API](docs/forward-api.md) · [Managed API](docs/managed-api.md),包含初始化、同步/异步调用、分页、SSE、文件传输,以及全部资源方法的参数、返回类型与 HTTP 路由。
5
+
Full API reference: [Forward API](docs/forward-api.md) · [Managed API](docs/managed-api.md) — covering initialization, sync and async calls, pagination, SSE, file transfer, and the parameters, return types, and HTTP routes of every resource method.
6
6
7
-
## 安装与配置
7
+
## Installation and configuration
8
+
9
+
```bash
10
+
python -m pip install qca
11
+
```
12
+
13
+
The package is still in pre-release, so the command above resolves to the latest `0.0.1.devN` build. To work from a checkout of this repository instead:
`from qca.forward import Client`and`from qca.managed import Client` are equivalent entry points. The two modes are instantiated independently and use their own resources and types.
30
35
31
-
|配置| Forward | Managed |
36
+
|Setting| Forward | Managed |
32
37
|---|---|---|
33
-
|令牌|`QODER_ACCESS_TOKEN`|`QODER_ACCESS_TOKEN`|
34
-
| API 根地址|`QODER_FORWARD_BASE_URL`|`QODER_BASE_URL`|
Explicit arguments take precedence over environment variables. The clients never read `.env`; only the examples load`.env.live`. The China endpoints have to be configured explicitly:
片段会创建资源。包含执行断言和清理的完整用例见 [examples](examples/README.md)。Forward 还提供 Schedule、Batch、Channel;Managed 提供 Deployment、Dream、自托管环境 Work API。
87
+
These snippets create real resources. For complete scenarios with execution assertions and cleanup, see [examples](examples/README.md). Forward additionally offers Schedule, Batch, and Channel; Managed offers Deployment, Dream, and the Work API for self-hosted environments.
The code below works with either client. Reuse `session_id` throughout a conversation, and reuse one idempotency key across HTTP retries of the same logical message.
SDK 不自动重连 SSE。保存 `stream.last_event_id`,重连时通过 `Last-Event-ID`恢复,不要重发已被接收的消息。`event_start`、`event_delta`是预览,最终事件会再次包含完整内容;同一个 ID 的增量事件不会被去重。idle 可能表示等待确认或达到预算,业务成功还需检查 `stop_reason`和最终回复。
117
+
The SDK does not reconnect a stream on its own. Persist `stream.last_event_id` and resume through the `Last-Event-ID`header rather than resending messages the server already accepted. `event_start` and `event_delta`are previews: the final event carries the complete content again, and delta events sharing an ID are not deduplicated. An idle status can also mean the session is waiting for a confirmation or has reached its budget, so check `stop_reason`and the final reply before treating a run as successful.
Async streams use `async with await client.sessions.events.stream(...)`. Complete snippets are in the [Forward async example](examples/forward/async_session.py) and the [Managed async example](examples/managed/async_session.py). Local files are read in a worker thread; network requests go directly through the async HTTP client.
133
138
134
-
## 参数与响应
139
+
## Parameters and responses
135
140
136
-
方法使用 snake_case、关键字参数和类型注解。嵌套资源的目标 ID 可以作为位置参数,祖先 ID 必须具名:
141
+
Methods use snake_case names, keyword arguments, and type annotations. The target ID of a nested resource may be positional, while ancestor IDs must be named:
Requests are described by `TypedDict`s in each mode's `types/*_params.py`. Pass plain dicts for nested parameters, and pass the matching string, dict, or list for unions. Responses are Pydantic models: fields are accessed directly, and unknown fields are preserved.
144
149
145
150
```python
146
151
from qca importNOT_GIVEN
147
152
148
-
client.identities.update("identity-id", name=NOT_GIVEN) #不发送 name
Whether a field can be cleared is decided by the server. Every method accepts `extra_headers`, `extra_query`, `extra_body`, and `timeout`; extra values take precedence over method arguments. Empty arrays, empty objects, `0`, and `false` are all preserved.
160
165
161
-
## 分页
166
+
## Pagination
162
167
163
168
```python
164
169
page = client.sessions.list(limit=20)
165
-
print(page.data) #当前页
166
-
for session in page: #自动获取后续页
170
+
print(page.data) #current page
171
+
for session in page: #fetches subsequent pages automatically
167
172
print(session.id)
168
173
for page in client.sessions.list().iter_pages():
169
174
print(len(page.data))
170
175
```
171
176
172
-
SDK 按 Go API 区分 `after_id` / `before_id`与 `next_page`分页,后续请求保留过滤条件。游标不前进或循环时抛出异常。非分页列表响应(例如 Models)通过 `.data` 访问。
177
+
Following the API, the SDK distinguishes `after_id` / `before_id`cursors from `next_page`pagination and carries filters into subsequent requests. It raises if a cursor stops advancing or starts looping. Non-paginated list responses, such as Models, are read through `.data`.
173
178
174
-
## 错误、超时与重试
179
+
## Errors, timeouts, and retries
175
180
176
181
```python
177
182
from qca import APIConnectionError, APIStatusError, APITimeoutError
HTTP statuses map to `BadRequestError`, `AuthenticationError`, `PermissionDeniedError`, `NotFoundError`, `ConflictError`, `UnprocessableEntityError`, `RateLimitError`, and `InternalServerError`. Non-JSON error bodies are kept in `.body`. When a response cannot be decoded into its declared type, `APIResponseValidationError` is raised.
The default connect timeout is 10 seconds, and 60 seconds for the remaining HTTP phases. You can pass a float of seconds, an `httpx.Timeout`, or `None`; timeouts are measured per HTTP phase and per attempt. End-to-end deadlines are the caller's responsibility — async code can use `asyncio.wait_for`.
Up to 2 retries by default: GET/HEAD requests and requests carrying an `Idempotency-Key`are retried on connection errors, 408, 429, and 5xx; other requests without an idempotency key are retried on 429 only; 409 is never retried automatically. Within those constraints the SDK honors `x-should-retry`and a valid `Retry-After-Ms` / `Retry-After`, and otherwise backs off exponentially. An SSE stream that has already been established is not retried.
`client.with_options(max_retries=0, timeout=20)`returns a separately configured client that shares the same HTTP connection pool; closing either client closes that pool.
196
201
197
-
## 文件和自定义 HTTP
202
+
## Files and custom HTTP
198
203
199
204
```python
200
205
from pathlib import Path
@@ -205,9 +210,9 @@ with client.files.download(file.id) as content:
Uploads accept bytes, binary file objects, `Path`, and `(filename, content[, MIME type])`. File objects you provide stay yours to close; upload content is buffered so it can be replayed on retry. Metadata is JSON-encoded, and Skill relative paths are preserved in the multipart filename.
209
214
210
-
Files 下载先获取临时链接,再流式读取存储地址;API 认证、默认请求头、Cookie 不会发送到存储主机。Skill Version 下载直接返回 API 的二进制响应。异步下载使用 `await client.files.download(...)`、`await response.write_to_file(...)`。
215
+
A file download first obtains a temporary link and then streams from the storage endpoint; API credentials, default headers, and cookies are not sent to the storage host. A Skill version download returns the API's binary response directly. Async downloads use `await client.files.download(...)` and `await response.write_to_file(...)`.
211
216
212
217
```python
213
218
import httpx
@@ -219,37 +224,37 @@ with Forward(http_client=httpx.Client(proxy="http://localhost:8080")) as client:
Async clients accept an `httpx.AsyncClient`, and async raw responses are parsed with `await raw.parse()`. A dynamic token provider is passed as `credential=` and its`get_token()` is called on every HTTP attempt; async clients also accept an async `get_token()`. A static `access_token` takes precedence over a provider, and an explicit `Authorization` header takes precedence over both.
Use`with_streaming_response` when the response headers have to be inspected before the body is read. The connection is closed when the context exits:
225
230
226
231
```python
227
232
with client.models.with_streaming_response.list() as response:
228
233
print(response.headers)
229
234
models = response.parse()
230
235
```
231
236
232
-
异步版本使用 `async with client.models.with_streaming_response.list()`,通过 `await response.parse()` 解析正文;也可以按块迭代 `iter_bytes()` / `iter_lines()`。
237
+
The async form is `async with client.models.with_streaming_response.list()`, with the body parsed through `await response.parse()`; the payload can also be iterated in chunks with `iter_bytes()` / `iter_lines()`.
0 commit comments