
















@@ -188,73 +188,81 @@ async function fetchOpenRouterModels(
188188fetchImpl: typeof fetch,
189189timeoutMs: 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;
226221227-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}
259267260268async function probeTool(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。