@@ -14,15 +14,9 @@ export type StreamingGuess = {
1414 * Note: Probing will tee() the stream and return a new Response object.
1515 *
1616 * @param res - The Response to classify
17- * @param opts.timeoutMs - Probe timeout in ms (default: 25)
1817 * @returns Classification result with safe-to-return Response
1918 */
20- export async function classifyResponseStreaming (
21- res : Response ,
22- opts : { timeoutMs ?: number } = { } ,
23- ) : Promise < StreamingGuess > {
24- const timeoutMs = opts . timeoutMs ?? 25 ;
25-
19+ export async function classifyResponseStreaming ( res : Response ) : Promise < StreamingGuess > {
2620 if ( ! res . body ) {
2721 return { response : res , isStreaming : false } ;
2822 }
@@ -40,48 +34,27 @@ export async function classifyResponseStreaming(
4034 return { response : res , isStreaming : false } ;
4135 }
4236
43- // Uncertain - probe the stream to determine behavior
37+ // Probe the stream by trying to read first chunk immediately
4438 // After tee(), must use the teed stream (original is locked)
4539 const [ probeStream , passStream ] = res . body . tee ( ) ;
4640 const reader = probeStream . getReader ( ) ;
4741
48- const probeResult = await Promise . race ( [
49- // Try to read first chunk
50- ( async ( ) => {
51- try {
52- const { value, done } = await reader . read ( ) ;
53- reader . releaseLock ( ) ;
54-
55- if ( done ) {
56- return { arrivedBytes : 0 , done : true } ;
57- }
42+ try {
43+ const { done } = await reader . read ( ) ;
44+ reader . releaseLock ( ) ;
5845
59- const bytes =
60- value && typeof value === 'object' && 'byteLength' in value
61- ? ( value as { byteLength : number } ) . byteLength
62- : 0 ;
63- return { arrivedBytes : bytes , done : false } ;
64- } catch {
65- return { arrivedBytes : 0 , done : false } ;
66- }
67- } ) ( ) ,
68- // Timeout if first chunk takes too long
69- new Promise < { arrivedBytes : number ; done : boolean } > ( resolve =>
70- setTimeout ( ( ) => resolve ( { arrivedBytes : 0 , done : false } ) , timeoutMs ) ,
71- ) ,
72- ] ) ;
46+ const teededResponse = new Response ( passStream , res ) ;
7347
74- const teededResponse = new Response ( passStream , res ) ;
48+ if ( done ) {
49+ // Stream completed immediately - buffered (empty body)
50+ return { response : teededResponse , isStreaming : false } ;
51+ }
7552
76- // Determine if streaming based on probe result
77- if ( probeResult . done ) {
78- // Stream completed immediately - buffered
79- return { response : teededResponse , isStreaming : false } ;
80- } else if ( probeResult . arrivedBytes === 0 ) {
81- // Timeout waiting - definitely streaming
82- return { response : teededResponse , isStreaming : true } ;
83- } else {
84- // Got chunk quickly - streaming if no Content-Length
53+ // Got data - treat as streaming if no Content-Length header
8554 return { response : teededResponse , isStreaming : contentLength == null } ;
55+ } catch {
56+ reader . releaseLock ( ) ;
57+ // Error reading - treat as non-streaming to be safe
58+ return { response : new Response ( passStream , res ) , isStreaming : false } ;
8659 }
8760}
0 commit comments