Skip to content

Commit de70a92

Browse files
authored
feat(forward): support Drive files and managed tool configuration (#19)
1 parent c5223eb commit de70a92

22 files changed

Lines changed: 1546 additions & 1 deletion

‎.env.live.example‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,8 @@ QODER_REALTIME_GLOBAL_SAT=
5151
# Optional raw PCM16 input (16 kHz mono little-endian); otherwise sends short text.
5252
# QODER_REALTIME_CN_PCM_FILE=
5353
# QODER_REALTIME_GLOBAL_PCM_FILE=
54+
55+
# Forward Drive Beta lifecycle (creates isolated Identities; no model execution).
56+
# Uses QODER_FORWARD_CN_PAT, QODER_FORWARD_GLOBAL_PAT, QODER_SA_CN_KEY,
57+
# and QODER_SA_GLOBAL_KEY. Never point clear at a shared Identity.
58+
QODER_DRIVE_LIVE_ALLOW_WRITE=false

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ existing `0.1.0` release; earlier development prereleases are not listed.
55

66
## [Unreleased]
77

8+
### Added
9+
10+
- Forward Drive Beta: typed directory listing, upload/download signed URLs, entry deletion and Drive clearing, with required Identity scope, independent cursor pagination, service ordering and canonical directory query encoding.
11+
- Template `managed_tool_config.enabled_tools` in create/update requests and responses, including omission, empty-list and null semantics. Runnable Drive examples keep storage requests separate from QCA authentication; opt-in CN/Global lifecycle tests cover PAT, admin SAT and Identity SAT.
12+
813
## [0.5.0]
914

1015
### Added

‎Makefile‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,7 @@ test-live-realtime:
4545

4646
test-live-sa-tokens:
4747
QODER_LIVE_ENV_FILE="$(LIVE_ENV_FILE)" $(PYTHON) -m pytest tests/sa/test_tokens_live.py -m integration -v -s
48+
49+
.PHONY: test-live-drive
50+
test-live-drive:
51+
QODER_DRIVE_RUN_LIVE=1 QODER_LIVE_ENV_FILE="$(LIVE_ENV_FILE)" $(PYTHON) -m pytest tests/integration/test_drive.py -m integration -v -s

‎README.md‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,57 @@ credential = client.vaults.credentials.retrieve("credential-id", vault_id="vault
609609
memory = client.memory_stores.memories.retrieve("memory-id", memory_store_id="store-id")
610610
```
611611

612+
## Forward Drive (Beta)
613+
614+
Drive is a Beta API. It uses `entries` / `next_page_token`, not the ordinary
615+
resource paginator. Pass `identity_id` even with an Identity SAT, preserve the
616+
server order, and reuse a cursor only within the same Identity, directory and
617+
authentication scope. Paths are relative; the SDK preserves slashes when encoding
618+
the list query and leaves path validation to the service.
619+
620+
Upload/download methods return a signed URL, method, headers and expiry. Send the
621+
storage request with a separate HTTP client using only those returned headers;
622+
do not attach QCA credentials or log signed URLs. Replaying an `Idempotency-Key`
623+
does not renew the URL: use a new key or omit it when requesting a fresh URL.
624+
625+
Deleting a nonempty directory requires `recursive=true`; `clear` deletes the
626+
entire selected Identity Drive. Partial failures retain `drive_delete_partial`
627+
and `deleted_count` in the standard API error body. Direct Drive APIs do not
628+
require Template tool configuration.
629+
630+
```python
631+
page = client.drives.list_entries(identity_id=identity_id, path="reports", limit=20)
632+
for entry in page.entries:
633+
print(entry.path)
634+
if page.next_page_token:
635+
page = client.drives.list_entries(
636+
identity_id=identity_id, path="reports", page_token=page.next_page_token,
637+
)
638+
# Replace the complete managed-tool list, retaining any other tools you need.
639+
client.templates.update(template_id, managed_tool_config={"enabled_tools": ["drive"]})
640+
```
641+
642+
`AsyncForward` exposes the same methods with `await`. Run the
643+
[file lifecycle example](examples/forward/drive.py) with
644+
`python -m examples.forward.drive --region cn` (or `global`); it uses the shared
645+
PAT/SA configuration and creates a fresh Identity. A directory has `size=None`;
646+
a zero-byte file has `size=0`.
647+
For maintainers, `uv run make test-live-drive` tests CN/Global × PAT/admin
648+
SAT/Identity SAT with both sync and async clients.
649+
650+
To enable Agent-managed Drive tools, use Template `managed_tool_config.enabled_tools`.
651+
It is separate from `tools[].enabled_tools` and replaces the entire list; an empty
652+
list disables managed tools, omission preserves the setting, and `null` clears it.
653+
Full Agent Drive usage also requires the DeliverArtifacts tool. Internal
654+
`/forward-mcp` routes are invoked by the runtime and are not public SDK methods.
655+
656+
The Drive live suite requires `QODER_DRIVE_LIVE_ALLOW_WRITE=true`,
657+
`QODER_FORWARD_CN_PAT`, `QODER_FORWARD_GLOBAL_PAT`, `QODER_SA_CN_KEY`, and
658+
`QODER_SA_GLOBAL_KEY` in `.env.live` (or `LIVE_ENV_FILE`). It creates isolated
659+
Identities, verifies storage transfers, pagination, deletion, Identity isolation,
660+
and Template configuration, then clears only those new Identities. It does not
661+
run Agent/model tool execution.
662+
612663
## File uploads and downloads
613664

614665
Uploads accept `bytes`, a binary file object, a `Path`, or a `(filename, content[, content type])` tuple. Content is buffered so it can be replayed on retry; a file object you open stays yours to close.

0 commit comments

Comments
 (0)