@@ -1770,12 +1770,17 @@ async function handleResponsesInner(
17701770 // (Bun#32111 JS-sink segfault — text frames pass, the terminal block is
17711771 // lost). The eager single reader applies the same rewrites inline.
17721772 const win32EagerRewrite = isWin32EagerRewrite ( process . platform , needsClientRewrite ) ;
1773+ // A native tee branch cannot be closed at a Responses protocol terminal
1774+ // while its upstream HTTP connection remains open. Windows therefore
1775+ // needs the existing single-reader relay even without payload rewrites;
1776+ // otherwise Codex keeps thinking after response.completed.
1777+ const win32TerminalRelay = process . platform === "win32" ;
17731778 const eagerPath = selectEagerPath (
17741779 process . platform ,
17751780 needsClientRewrite ,
17761781 config . streamMode ?? "auto" ,
17771782 ) ;
1778- if ( eagerPath ?. useEagerRelay || win32EagerRewrite ) {
1783+ if ( eagerPath ?. useEagerRelay || win32EagerRewrite || win32TerminalRelay ) {
17791784 const turnAc = new AbortController ( ) ;
17801785 linkAbortSignal ( upstream , turnAc . signal ) ;
17811786 registerTurn ( turnAc , options . turnAdmissionLease ) ;
@@ -1811,7 +1816,9 @@ async function handleResponsesInner(
18111816 inspectChunk : chunk => inspector . feed ( chunk ) ,
18121817 finishInspection : ( ) => inspector . finish ( ) ,
18131818 disposeInspection : ( ) => inspector . dispose ( ) ,
1814- sawTerminal : ( ) => inspector . reported ( ) ,
1819+ // Stream lifetime follows the protocol terminal even when this request
1820+ // has no outcome callback configured (reported() would stay false).
1821+ sawTerminal : ( ) => inspector . terminalSeen ( ) ,
18151822 ...( win32EagerRewrite
18161823 ? { rewritePayload : composeSsePayloadRewrites ( ...payloadRewrites ) }
18171824 : { } ) ,
@@ -1829,9 +1836,9 @@ async function handleResponsesInner(
18291836 onClientCancel : ( ) => options . onNativePassthroughCancel ?.( ) ,
18301837 onDone : ( ) => unregisterTurn ( turnAc ) ,
18311838 } , win32EagerRewrite ? { rewriteBudget : translatorBudget } : undefined ) ;
1832- // selectEagerPath admits only no-rewrite traffic on both eligible platforms;
1833- // win32 rewrite traffic reaches this relay too, but with the payload rewrite
1834- // applied inline — never via an image/item-id JS pull wrapper (#32111, #864).
1839+ // Windows always reaches this relay so response.completed can close a
1840+ // keep-alive upstream. Rewrite traffic applies its payload transform
1841+ // inline — never via the Bun#32111-unsafe tee()+JS- pull chain ( #864).
18351842 if ( ! headers . has ( "content-type" ) ) headers . set ( "content-type" , "text/event-stream" ) ;
18361843 return markEagerRelaySseResponse (
18371844 markNativePassthroughSseResponse ( new Response ( eagerBody , {
@@ -1898,15 +1905,13 @@ async function handleResponsesInner(
18981905 ) ;
18991906 }
19001907 if ( ! headers . has ( "content-type" ) ) headers . set ( "content-type" , "text/event-stream" ) ;
1901- // win32 must keep the pure native relay (Bun#32111 JS-sink segfault); elsewhere a JS pull
1902- // relay is established practice (relayWithAbort, relaySseWithHeartbeat) and lets a
1903- // mid-stream reset end with a clean response.failed terminal instead of a raw socket error .
1908+ // Windows was handled by the eager terminal-aware branch above. Remaining
1909+ // tee traffic can use the JS relay to close on a protocol terminal and to
1910+ // convert a mid-stream reset into a clean response.failed event .
19041911 const rewrittenBody = payloadRewrites . length > 0
19051912 ? relaySseWithPayloadRewrite ( nativeBody , composeSsePayloadRewrites ( ...payloadRewrites ) , translatorBudget )
19061913 : nativeBody ;
1907- const clientBody = process . platform === "win32" && ! needsClientRewrite
1908- ? nativeBody
1909- : relaySseWithFailedTail ( rewrittenBody , upstream , reason => clientGone . abort ( reason ) ) ;
1914+ const clientBody = relaySseWithFailedTail ( rewrittenBody , upstream , reason => clientGone . abort ( reason ) ) ;
19101915 return markNativePassthroughSseResponse ( new Response ( clientBody , {
19111916 status : upstreamResponse . status ,
19121917 headers,
0 commit comments