@@ -30,6 +30,7 @@ import { ModelStatus } from "./model-status"
3030import { RuntimeFlags } from "@/effect/runtime-flags"
3131
3232const log = Log . create ( { service : "provider" } )
33+ const PROVIDER_TIMEOUT_DEFAULT = 300_000
3334
3435function shouldUseCopilotResponsesApi ( modelID : string ) : boolean {
3536 const match = / ^ g p t - ( \d + ) / . exec ( modelID )
@@ -85,6 +86,18 @@ function wrapSSE(res: Response, ms: number, ctl: AbortController) {
8586 } )
8687}
8788
89+ function timeoutController ( ms : number ) {
90+ const ctl = new AbortController ( )
91+ const id = setTimeout (
92+ ( ) => ctl . abort ( new DOMException ( `Provider request timed out after ${ ms } ms` , "TimeoutError" ) ) ,
93+ ms ,
94+ )
95+ return {
96+ signal : ctl . signal ,
97+ clear : ( ) => clearTimeout ( id ) ,
98+ }
99+ }
100+
88101function googleVertexAnthropicBaseURL ( project : string | undefined , location : string | undefined ) {
89102 if ( ! project ) return
90103 if ( location !== "eu" && location !== "us" ) return
@@ -1607,12 +1620,13 @@ export const layer = Layer.effect(
16071620 const fetchFn = customFetch ?? fetch
16081621 const opts = init ?? { }
16091622 const chunkAbortCtl = typeof chunkTimeout === "number" && chunkTimeout > 0 ? new AbortController ( ) : undefined
1623+ const requestTimeout = options [ "timeout" ] === false ? undefined : ( options [ "timeout" ] ?? PROVIDER_TIMEOUT_DEFAULT )
1624+ const requestTimeoutCtl = typeof requestTimeout === "number" ? timeoutController ( requestTimeout ) : undefined
16101625 const signals : AbortSignal [ ] = [ ]
16111626
16121627 if ( opts . signal ) signals . push ( opts . signal )
16131628 if ( chunkAbortCtl ) signals . push ( chunkAbortCtl . signal )
1614- if ( options [ "timeout" ] !== undefined && options [ "timeout" ] !== null && options [ "timeout" ] !== false )
1615- signals . push ( AbortSignal . timeout ( options [ "timeout" ] ) )
1629+ if ( requestTimeoutCtl ) signals . push ( requestTimeoutCtl . signal )
16161630
16171631 const combined = signals . length === 0 ? null : signals . length === 1 ? signals [ 0 ] : AbortSignal . any ( signals )
16181632 if ( combined ) opts . signal = combined
@@ -1639,7 +1653,7 @@ export const layer = Layer.effect(
16391653 ...opts ,
16401654 // @ts -ignore see here: https://github.com/oven-sh/bun/issues/16682
16411655 timeout : false ,
1642- } )
1656+ } ) . finally ( ( ) => requestTimeoutCtl ?. clear ( ) )
16431657
16441658 if ( ! chunkAbortCtl ) return res
16451659 return wrapSSE ( res , chunkTimeout , chunkAbortCtl )
0 commit comments