File tree Expand file tree Collapse file tree 4 files changed +25
-3
lines changed
Expand file tree Collapse file tree 4 files changed +25
-3
lines changed Original file line number Diff line number Diff line change @@ -845,7 +845,7 @@ const ProviderCapabilities = Schema.Struct({
845845 input : ProviderModalities ,
846846 output : ProviderModalities ,
847847 interleaved : ProviderInterleaved ,
848- systemMessage : Schema . Union ( [ Schema . Literal ( "single" ) , Schema . Literal ( "multiple" ) ] ) . optional ( ) ,
848+ systemMessage : Schema . optional ( Schema . Union ( [ Schema . Literal ( "single" ) , Schema . Literal ( "multiple" ) ] ) ) ,
849849} )
850850
851851const ProviderCacheCost = Schema . Struct ( {
Original file line number Diff line number Diff line change @@ -645,6 +645,15 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
645645 } ,
646646
647647 flush ( controller ) {
648+ // If the stream ended without a finish_reason and output is still
649+ // active, the stream was truncated — emit an error to trigger retry
650+ const hasActiveOutput = isActiveReasoning || isActiveText || toolCalls . some ( ( tc ) => ! tc . hasFinished )
651+ if ( finishReason . unified === "other" && finishReason . raw === undefined && hasActiveOutput ) {
652+ controller . enqueue ( {
653+ type : "error" ,
654+ error : new Error ( "Stream ended unexpectedly — no finish reason received while output was still active" ) ,
655+ } )
656+ }
648657 if ( isActiveReasoning ) {
649658 controller . enqueue ( {
650659 type : "reasoning-end" ,
Original file line number Diff line number Diff line change @@ -1028,6 +1028,15 @@ export function fromError(
10281028 } ,
10291029 { cause : e } ,
10301030 ) . toObject ( )
1031+ case e instanceof Error && e . message === "SSE read timed out" :
1032+ return new APIError (
1033+ {
1034+ message : "Stream read timed out — no data received within the chunk timeout window" ,
1035+ isRetryable : true ,
1036+ metadata : { code : "SSE_TIMEOUT" , message : e . message } ,
1037+ } ,
1038+ { cause : e } ,
1039+ ) . toObject ( )
10311040 case e instanceof Error :
10321041 return new NamedError . Unknown ( { message : errorMessage ( e ) } , { cause : e } ) . toObject ( )
10331042 default :
Original file line number Diff line number Diff line change @@ -63,14 +63,18 @@ export function retryable(error: Err) {
6363 return error . data . message . includes ( "Overloaded" ) ? "Provider is overloaded" : error . data . message
6464 }
6565
66- // Check for rate limit patterns in plain text error messages
66+ // Check for stream interruption and rate limit patterns in plain text error messages
6767 const msg = error . data ?. message
6868 if ( typeof msg === "string" ) {
6969 const lower = msg . toLowerCase ( )
7070 if (
7171 lower . includes ( "rate increased too quickly" ) ||
7272 lower . includes ( "rate limit" ) ||
73- lower . includes ( "too many requests" )
73+ lower . includes ( "too many requests" ) ||
74+ lower . includes ( "sse read timed out" ) ||
75+ lower . includes ( "connection reset" ) ||
76+ lower . includes ( "aborted" ) ||
77+ lower . includes ( "stream ended unexpectedly" )
7478 ) {
7579 return msg
7680 }
You can’t perform that action at this time.
0 commit comments