Skip to content

feat(runtime): stream binary responses to files - #193

Merged
samzong merged 2 commits into
mainfrom
feat/stream-binary-responses
Oct 3, 2026
Merged

samzong merged 2 commits into
mainfrom
feat/stream-binary-responses

Conversation

@samzong

@samzong samzong commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Closes #121.

  • Codegen classifies an operation as a binary download when its success response is a non-JSON, non-streaming media type with a binary schema (type: file, format: binary) or a known binary media type (application/octet-stream, application/pdf, application/zip, application/gzip, image/*, audio/*, video/*, font/*, excluding +xml). An operation with any 2xx response that declares JSON or a streaming type is not binary.
  • Binary commands get --output-file <new-path> (or - for stdout) and stream the response without buffering it. The flag is required: without it the command fails with usage / exit 2 before resolving a host or sending a request. The catalog exposes the actual flag name as output.binary.flag, and __lathe verify checks that the flag exists.
  • Files are written to a hidden 0600 temporary file in the target directory and linked into place only after a complete 2xx response, so an existing path is never overwritten. Existing paths, missing directories, and unwritable directories fail before the request. Non-2xx responses, cancellation (Ctrl-C), and read failures remove the temporary file.
  • When the declared type is specific (for example application/pdf), a 2xx response whose actual Content-Type is JSON or HTML is rejected with api_error / exit 3 before any byte is written. Generic declarations (application/octet-stream, wildcards) accept any stored type.
  • A failure after the response was received (the final link step) is a general error, exit 1, stating that the request completed and the file was not written.
  • Binary commands do not register --wait. Workflow steps that call a binary operation fail codegen. runtime.InvokeOperation keeps buffering the response.
  • Generated Skills tell agents to pass --<output.binary.flag> with a new path, or - only when piping to another program.

Verification

  • make check passed.
  • go test -race ./pkg/runtime/... ./pkg/lathe/... ./internal/codegen/... ./internal/lathecmd/... passed.
  • examples/richapi: lathe codegen -cache fixtures, build, __lathe verify --json returned ok: true; Reports_Download reports output.binary.flag: output-file with catalog_schema_version 27 after merging main.
  • Against a local server with an isolated config dir: a 3 MiB download matched byte for byte with mode 600; - piped into cmp matched; an existing target path failed with exit 2 and left the file unchanged; a missing flag failed with exit 2.
  • An independent review exercised a real CLI against an adversarial server: gzip, truncated gzip and chunked bodies, 429/500 retries, redirects, 401/404, symlinked targets, missing and read-only directories, SIGINT mid-transfer, --debug, and 200 responses with JSON, HTML, and application/problem+json. Its findings were fixed and re-verified.

Not verified: the Rename fallback for filesystems without hard links (for example exFAT); termination by a signal other than SIGINT may leave the hidden temporary file next to the target, as documented.

Compatibility

  • runtime.SchemaVersion 20 and runtime.CatalogSchemaVersion 27; regenerate downstream CLIs.
  • After regeneration, binary operations require --output-file; the previous default of printing the bytes, or -o raw > file, now fails with exit 2. Use --output-file - to keep writing to stdout.
  • Binary operations no longer accept --wait and cannot be used as workflow steps.

Checklist

  • Tests or focused verification cover the changed surface.
  • User-facing behavior changes are documented.
  • Generated output under internal/generated/, .cache/, and ad-hoc skills/<cli-name>/ directories is not committed.
  • Commits are signed off when this is ready to merge.

Signed-off-by: samzong <samzong.lu@gmail.com>
@ghfind-review ghfind-review Bot added the review: top ghfind author score; see https://ghfind.com label Oct 3, 2026
@codspeed

codspeed Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will improve performance by 11.09%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚡ 1 improved benchmark
✅ 20 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
⚡ json-large 3.8 ms 3.4 ms +11.09%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing feat/stream-binary-responses (bbedc0a) with main (bad7939)

Open in CodSpeed

…sponses

Signed-off-by: samzong <samzong.lu@gmail.com>

# Conflicts:
#	docs/contracts.md
#	internal/codegen/render/skill_test.go
@samzong
samzong marked this pull request as ready for review October 3, 2026 19:06
@samzong
samzong merged commit 34a1e47 into main Oct 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: top ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(runtime): stream binary responses to stdout or files

1 participant