mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: add timeouts to model fetchers and send router models incrementally
Addresses #11747 where blocked DNS for provider domains (e.g. openrouter.ai, router.requesty.ai) caused all providers to hang until the DNS timeout expired, even for providers with working DNS. Changes: 1. Add 10-second timeout to axios.get() calls in openrouter.ts, requesty.ts, unbound.ts, and vercel-ai-gateway.ts fetchers. The roo.ts and litellm.ts fetchers already had timeouts. 2. Send router models incrementally in the requestRouterModels handler: each provider posts its models to the webview as soon as it resolves, rather than waiting for all providers to finish via Promise.allSettled. A final aggregated message is still sent for backward compatibility.
This commit is contained in:
parent
0aea65d1e6
commit
3a054a6a9a
5 changed files with 22 additions and 8 deletions
|
|
@ -99,7 +99,7 @@ export async function getOpenRouterModels(options?: ApiHandlerOptions): Promise<
|
|||
const baseURL = options?.openRouterBaseUrl || "https://openrouter.ai/api/v1"
|
||||
|
||||
try {
|
||||
const response = await axios.get<OpenRouterModelsResponse>(`${baseURL}/models`)
|
||||
const response = await axios.get<OpenRouterModelsResponse>(`${baseURL}/models`, { timeout: 10_000 })
|
||||
const result = openRouterModelsResponseSchema.safeParse(response.data)
|
||||
const data = result.success ? result.data.data : response.data.data
|
||||
|
||||
|
|
@ -147,7 +147,9 @@ export async function getOpenRouterModelEndpoints(
|
|||
const baseURL = options?.openRouterBaseUrl || "https://openrouter.ai/api/v1"
|
||||
|
||||
try {
|
||||
const response = await axios.get<OpenRouterModelEndpointsResponse>(`${baseURL}/models/${modelId}/endpoints`)
|
||||
const response = await axios.get<OpenRouterModelEndpointsResponse>(`${baseURL}/models/${modelId}/endpoints`, {
|
||||
timeout: 10_000,
|
||||
})
|
||||
const result = openRouterModelEndpointsResponseSchema.safeParse(response.data)
|
||||
const data = result.success ? result.data.data : response.data.data
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export async function getRequestyModels(baseUrl?: string, apiKey?: string): Prom
|
|||
const resolvedBaseUrl = toRequestyServiceUrl(baseUrl)
|
||||
const modelsUrl = new URL("v1/models", resolvedBaseUrl)
|
||||
|
||||
const response = await axios.get(modelsUrl.toString(), { headers })
|
||||
const response = await axios.get(modelsUrl.toString(), { headers, timeout: 10_000 })
|
||||
const rawModels = response.data.data
|
||||
|
||||
for (const rawModel of rawModels) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export async function getUnboundModels(apiKey?: string | null): Promise<Record<s
|
|||
headers["Authorization"] = `Bearer ${apiKey}`
|
||||
}
|
||||
|
||||
const response = await axios.get("https://api.getunbound.ai/models", { headers })
|
||||
const response = await axios.get("https://api.getunbound.ai/models", { headers, timeout: 10_000 })
|
||||
const rawModels = response.data?.data ?? response.data
|
||||
|
||||
for (const rawModel of rawModels) {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export async function getVercelAiGatewayModels(options?: ApiHandlerOptions): Pro
|
|||
const baseURL = "https://ai-gateway.vercel.sh/v1"
|
||||
|
||||
try {
|
||||
const response = await axios.get<VercelAiGatewayModelsResponse>(`${baseURL}/models`)
|
||||
const response = await axios.get<VercelAiGatewayModelsResponse>(`${baseURL}/models`, { timeout: 10_000 })
|
||||
const result = vercelAiGatewayModelsResponseSchema.safeParse(response.data)
|
||||
const data = result.success ? result.data.data : response.data.data
|
||||
|
||||
|
|
|
|||
|
|
@ -956,10 +956,23 @@ export const webviewMessageHandler = async (
|
|||
await flushModels(targetCandidate.options, true)
|
||||
}
|
||||
|
||||
// Fetch models incrementally: send each provider's models to the webview
|
||||
// as soon as they resolve, rather than waiting for all providers to finish.
|
||||
// This ensures providers with working DNS are available immediately while
|
||||
// blocked providers fail gracefully in the background (see #11747).
|
||||
const results = await Promise.allSettled(
|
||||
modelFetchPromises.map(async ({ key, options }) => {
|
||||
const models = await safeGetModels(options)
|
||||
return { key, models } // The key is `ProviderName` here.
|
||||
|
||||
// Send this provider's models to the webview immediately.
|
||||
routerModels[key] = models
|
||||
provider.postMessageToWebview({
|
||||
type: "routerModels",
|
||||
routerModels: { ...routerModels },
|
||||
values: providerFilter ? { provider: requestedProvider } : undefined,
|
||||
})
|
||||
|
||||
return { key, models }
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -968,8 +981,6 @@ export const webviewMessageHandler = async (
|
|||
|
||||
if (result.status === "fulfilled") {
|
||||
routerModels[routerName] = result.value.models
|
||||
|
||||
// Ollama and LM Studio settings pages still need these events. They are not fetched here.
|
||||
} else {
|
||||
// Handle rejection: Post a specific error message for this provider.
|
||||
const errorMessage = result.reason instanceof Error ? result.reason.message : String(result.reason)
|
||||
|
|
@ -986,6 +997,7 @@ export const webviewMessageHandler = async (
|
|||
}
|
||||
})
|
||||
|
||||
// Send final aggregated message for backward compatibility.
|
||||
provider.postMessageToWebview({
|
||||
type: "routerModels",
|
||||
routerModels,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue