@@ -188,73 +188,81 @@ async function fetchOpenRouterModels(
188188 fetchImpl : typeof fetch ,
189189 timeoutMs : number ,
190190) : Promise < OpenRouterModelMeta [ ] > {
191- const res = await withTimeout ( timeoutMs , ( signal ) =>
192- fetchImpl ( OPENROUTER_MODELS_URL , {
193- headers : { Accept : "application/json" } ,
194- signal,
195- } ) ,
196- ) ;
197- if ( ! res . ok ) {
198- throw new Error ( `OpenRouter /models failed: HTTP ${ res . status } ` ) ;
199- }
200- const payload = ( await res . json ( ) ) as { data ?: unknown } ;
201- const entries = Array . isArray ( payload . data ) ? payload . data : [ ] ;
202-
203- return entries
204- . map ( ( entry ) => {
205- if ( ! entry || typeof entry !== "object" ) {
206- return null ;
207- }
208- const obj = entry as Record < string , unknown > ;
209- const id = normalizeOptionalString ( obj . id ) ?? "" ;
210- if ( ! id ) {
211- return null ;
212- }
213- const name = typeof obj . name === "string" && obj . name . trim ( ) ? obj . name . trim ( ) : id ;
214-
215- const contextLength =
216- typeof obj . context_length === "number" && Number . isFinite ( obj . context_length )
217- ? obj . context_length
218- : null ;
219-
220- const maxCompletionTokens =
221- typeof obj . max_completion_tokens === "number" && Number . isFinite ( obj . max_completion_tokens )
222- ? obj . max_completion_tokens
223- : typeof obj . max_output_tokens === "number" && Number . isFinite ( obj . max_output_tokens )
224- ? obj . max_output_tokens
191+ let res : Response | undefined ;
192+ try {
193+ res = await withTimeout ( timeoutMs , ( signal ) =>
194+ fetchImpl ( OPENROUTER_MODELS_URL , {
195+ headers : { Accept : "application/json" } ,
196+ signal,
197+ } ) ,
198+ ) ;
199+ if ( ! res . ok ) {
200+ throw new Error ( `OpenRouter /models failed: HTTP ${ res . status } ` ) ;
201+ }
202+ const payload = ( await res . json ( ) ) as { data ?: unknown } ;
203+ const entries = Array . isArray ( payload . data ) ? payload . data : [ ] ;
204+
205+ return entries
206+ . map ( ( entry ) => {
207+ if ( ! entry || typeof entry !== "object" ) {
208+ return null ;
209+ }
210+ const obj = entry as Record < string , unknown > ;
211+ const id = normalizeOptionalString ( obj . id ) ?? "" ;
212+ if ( ! id ) {
213+ return null ;
214+ }
215+ const name = typeof obj . name === "string" && obj . name . trim ( ) ? obj . name . trim ( ) : id ;
216+
217+ const contextLength =
218+ typeof obj . context_length === "number" && Number . isFinite ( obj . context_length )
219+ ? obj . context_length
225220 : null ;
226221
227- const supportedParameters = Array . isArray ( obj . supported_parameters )
228- ? normalizeStringEntries (
229- obj . supported_parameters . filter ( ( value ) => typeof value === "string" ) ,
230- )
231- : [ ] ;
232-
233- const supportedParametersCount = supportedParameters . length ;
234- const supportsToolsMeta = supportedParameters . includes ( "tools" ) ;
235-
236- const modality =
237- typeof obj . modality === "string" && obj . modality . trim ( ) ? obj . modality . trim ( ) : null ;
238-
239- const inferredParamB = inferParamBFromIdOrName ( `${ id } ${ name } ` ) ;
240- const createdAtMs = normalizeCreatedAtMs ( obj . created_at ) ;
241- const pricing = parseOpenRouterPricing ( obj . pricing ) ;
242-
243- return {
244- id,
245- name,
246- contextLength,
247- maxCompletionTokens,
248- supportedParameters,
249- supportedParametersCount,
250- supportsToolsMeta,
251- modality,
252- inferredParamB,
253- createdAtMs,
254- pricing,
255- } satisfies OpenRouterModelMeta ;
256- } )
257- . filter ( ( entry ) : entry is OpenRouterModelMeta => Boolean ( entry ) ) ;
222+ const maxCompletionTokens =
223+ typeof obj . max_completion_tokens === "number" &&
224+ Number . isFinite ( obj . max_completion_tokens )
225+ ? obj . max_completion_tokens
226+ : typeof obj . max_output_tokens === "number" && Number . isFinite ( obj . max_output_tokens )
227+ ? obj . max_output_tokens
228+ : null ;
229+
230+ const supportedParameters = Array . isArray ( obj . supported_parameters )
231+ ? normalizeStringEntries (
232+ obj . supported_parameters . filter ( ( value ) => typeof value === "string" ) ,
233+ )
234+ : [ ] ;
235+
236+ const supportedParametersCount = supportedParameters . length ;
237+ const supportsToolsMeta = supportedParameters . includes ( "tools" ) ;
238+
239+ const modality =
240+ typeof obj . modality === "string" && obj . modality . trim ( ) ? obj . modality . trim ( ) : null ;
241+
242+ const inferredParamB = inferParamBFromIdOrName ( `${ id } ${ name } ` ) ;
243+ const createdAtMs = normalizeCreatedAtMs ( obj . created_at ) ;
244+ const pricing = parseOpenRouterPricing ( obj . pricing ) ;
245+
246+ return {
247+ id,
248+ name,
249+ contextLength,
250+ maxCompletionTokens,
251+ supportedParameters,
252+ supportedParametersCount,
253+ supportsToolsMeta,
254+ modality,
255+ inferredParamB,
256+ createdAtMs,
257+ pricing,
258+ } satisfies OpenRouterModelMeta ;
259+ } )
260+ . filter ( ( entry ) : entry is OpenRouterModelMeta => Boolean ( entry ) ) ;
261+ } finally {
262+ if ( res && ! res . bodyUsed ) {
263+ await res . body ?. cancel ( ) . catch ( ( ) => undefined ) ;
264+ }
265+ }
258266}
259267
260268async function probeTool (
0 commit comments