Skip to content

PIGS-1096 - Presigned URLs, streaming upload/download, and progress bars - #15

Merged
brianom merged 3 commits into
pigs-1096-optimize-benchmarkfrom
pigs-1096-presigned-uploads-streaming
Sep 10, 2026
Merged

brianom merged 3 commits into
pigs-1096-optimize-benchmarkfrom
pigs-1096-presigned-uploads-streaming

Conversation

@RogerThomas

Copy link
Copy Markdown
Contributor

Summary

  • Switched file uploads to the platform's presigned-URL flow (mint a fresh pair, stream the file to it, submit an application/vnd.gonitro.url+json file reference) instead of inlining raw bytes into the multipart request
  • Stream both the upload and the async job's result download in chunks with a live rich progress bar, instead of buffering whole files in memory
  • BaseOAuthClient.build() is now a context-managed factory backed by two httpx2 clients — one authenticated against the platform, one plain for presigned/arbitrary URLs, so the platform bearer token never leaks onto them
  • Rewrote the SSE job-status handling on httpx2's native SSE support with a discriminated pydantic union (ProgressUpdate/StatusUpdate/Redirect), replacing the hand-rolled line parser
  • Fixed _request_async_bytes fetching the job's JSON representation instead of the actual result file (it relied on an Accept header the API doesn't honor)
  • Split benchmark.OperationResult into OperationSuccess/OperationFailure so a run's fields are only ever the ones that outcome can actually produce
  • Added FatalError (a SystemExit subclass) for clean, traceback-free CLI errors on user-facing validation failures
  • Added services.OptimizerService as a small facade over PlatformAPIClient for the optimize workflow, and wired optimize_benchmark.py through it
  • Assorted cleanup: MIME type lookup by extension instead of the stdlib mimetypes module, httpx2 status codes instead of hardcoded ints, and other small consistency fixes across the API clients

Test plan

  • ruff check . and pyright clean across the whole samples/python project
  • End-to-end tests against local fake servers for: single-file operations (convert/redact/etc.), merge (multi-file), the full async optimize job flow (submit → SSE progress → result download), and the streaming upload/download progress bars (verified byte-for-byte content integrity via SHA-256 on a multi-MB file)
  • Verified terminal output rendering with pyte (real terminal emulation) to confirm the progress bars don't corrupt surrounding CLI output
  • Manual run against the real API (task optimize-benchmark INPUT_DIR=... OUTPUT_DIR=...)

RogerThomas and others added 3 commits September 10, 2026 14:40
…gress bars

- Add BaseOAuthClient.build() as a context-managed factory, backed by two
  httpx2 clients: one authenticated against the platform, one plain for
  presigned/arbitrary URLs so the platform bearer token never leaks onto them
- Switch every file upload to the platform's presigned-URL flow (mint a
  fresh pair, stream the file to it, submit an application/vnd.gonitro.url+json
  file reference) instead of inlining raw bytes into the multipart request
- Stream both the upload and the async job's result download in chunks with
  a live rich progress bar, instead of buffering whole files in memory
- Rewrite PlatformAPIClient's SSE job-status handling on httpx2's native SSE
  support with a discriminated pydantic union (ProgressUpdate/StatusUpdate/
  Redirect) validated via TypeAdapter, replacing the hand-rolled line parser
- Fix _request_async_bytes fetching the job's JSON representation instead of
  the actual result file (it relied on an Accept header the API doesn't honor)
- Split benchmark.OperationResult into OperationSuccess/OperationFailure so
  a run's fields are only ever the ones that outcome can actually produce
- Add FatalError (a SystemExit subclass) for clean, traceback-free CLI errors
  on user-facing validation failures, replacing scattered print+exit pairs
- Add services.OptimizerService as a small facade over PlatformAPIClient for
  the optimize workflow, and wire optimize_benchmark.py through it
- Assorted cleanup: MIME type lookup by extension instead of the stdlib
  mimetypes module, httpx2 status codes instead of hardcoded ints, and other
  small consistency fixes across the API clients

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…L job flow

Every PlatformAPIClient operation now goes through the async job flow
(submit with Prefer: respond-async, follow the SSE status stream, fetch
the result) with the file uploaded via a presigned URL, matching the
pattern optimize() already used — factored the shared submit/poll/fetch
logic into _submit_async_job.

extract_text is the deliberate exception: it stays on a synchronous,
non-presigned request, for operations known to always run against small,
bounded documents where the extra round trip isn't worth it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@brianom brianom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused on optimize benchmark tool, looks good

@brianom
brianom merged commit a626027 into pigs-1096-optimize-benchmark Sep 10, 2026
2 checks passed
@brianom
brianom deleted the pigs-1096-presigned-uploads-streaming branch September 10, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants