mirror of
https://github.com/Comfy-Org/comfy-remote-nodes.git
synced 2026-11-04 23:37:22 +00:00
[PR #9] [MERGED] feat(serialization): externalize oversize image batch envelopes via per-frame presigned URIs #9
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-remote-nodes#9
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/comfy-remote-nodes/pull/9
Author: @Kosinkadink
Created: 5/15/2026
Status: ✅ Merged
Merged: 5/15/2026
Merged by: @Kosinkadink
Base:
main← Head:feat/batch-envelope-externalization📝 Commits (1)
6433a46feat(serialization): externalize oversize image batch envelopes via per-frame presigned URIs📊 Changes
3 files changed (+131 additions, -3 deletions)
View changed files
📝
client.py(+11 -0)📝
protocol.py(+14 -0)📝
serialization.py(+106 -3)📄 Description
Summary
The pre-existing
serialization.maybe_externalizeonly inspected the singletondatafield, so a multi-frameframes=[…]IMAGE envelope whose summed base64 payload crossed the 8 MiBDEFAULT_MAX_INLINE_PAYLOAD_BYTEScap silently rode the wire as a 30+ MiB POST body — defeating the entire reason the cap exists. A 9× 2048² Flux2 reference batch hits ~200 MB base64 inline; that's the worst-case the new path is designed for.This PR adds the client side of the lockstep fix: detect oversize multi-frame batches (sum of per-frame raw bytes), upload each frame as an individual presigned PUT in parallel via
asyncio.gather, and rewrite the envelope to the newimage:png_base64_batch_uriencoding with a parallelurislist. Server side closes the loop with a matching encoding-string dispatch inresolve_image_envelope_pngs.Per-frame URIs (NOT a tar/zip blob) compose with the existing per-frame fetch helpers and let the server fetch in parallel.
Changes
protocol.pyCapability.IMAGE_PNG_BASE64_BATCH_URI = "image:png_base64_batch_uri"token next toIMAGE_PNG_BASE64_BATCH. Comment block matches the server-side copy so the two stay byte-comparable.client.pyCapability.IMAGE_PNG_BASE64_BATCH_URItoCLIENT_CAPABILITIESso the server knows this client can emit the externalised batch shape. Comment notes the opportunistic posture (any input that already acceptspng_base64_batchtransparently accepts the externalised variant — no descriptor opt-in needed).serialization.pymaybe_externalizenow branches on payload shape: ifenvelope["frames"]is a populated list, dispatch to the new_maybe_externalize_batchhelper; otherwise fall through to the existing singleton-datapath. Docstring expanded to describe both shapes and the encoding-flip-on-spill behaviour._maybe_externalize_batchhelper sums per-frame raw bytes (len(b64) * 3 // 4), short-circuits when the batch fits under the cap, and otherwise uploads every frame in parallel viaasyncio.gather(preserves frame ordering — critical because Flux2 mapsuris[k]→input_image_{k+1}1:1) before rewriting the envelope to{type, encoding: png_base64_batch_uri, uris: [...], shape, dtype, color_space}withframesstripped.import asyncioadded at module top soasyncio.gatheris available without per-call imports.Verification
protocol.py,serialization.py,client.pysucceeds.comfy_api_nodes.util.clientshim and a stubbedupload_asset):{type: image, encoding: png_base64_batch_uri, uris: ['…/asset/1','…/asset/2','…/asset/3'], shape: [3,1,1,3], dtype: uint8, color_space: srgb}withframesstripped.dataenvelope (10 MiB raw, cap=8 MiB) → still gets the legacydata → uriswap (existing path unaffected).Capability.IMAGE_PNG_BASE64_BATCH_URI in CLIENT_CAPABILITIESholds.Lockstep
Paired server PR: https://github.com/Comfy-Org/comfy-rnp-server/pull/14 (
feat/batch-envelope-externalization).Server PR was opened first because the wire shape needs a server resolver to be meaningful — the orchestrator merges them in lockstep order.
Capability gating posture:
IMAGE_PNG_BASE64_BATCH_URIis opportunistic — this client emits it whenever a batch envelope it produced overflows the inline cap, regardless of whether the descriptor'sinput_serializationlists it. Server accepts on any image input that already acceptspng_base64_batchvia the sharedresolve_image_envelope_pngsdispatch. No new descriptor fields, no per-provider opt-in, norequired_capabilitieschanges — matches the spec's "Default: clients advertise the cap, server accepts it on any image input that already acceptspng_base64_batch. Don't add a new descriptor demand unless a provider needs it."Output-side decoder: server providers emit
png_base64_batch(or single-framepng_base64) on responses today; the URI shape is consumed on input only, so the client decoder (_DECODERS/_decode_image_batch_envelope) is unchanged. The existingdecode_image_envelopealready dispatches on theencodingstring (not field presence), so adding apng_base64_batch_uridecode branch is a drop-in if a future provider starts emitting the URI shape on outputs. Logged as a known follow-up.Do NOT merge until the paired server PR is merged — the orchestrator merges them in lockstep order.
Amp-Thread-ID: T-019e29b4-d606-7278-8584-52910661c981
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.