fix: add 5s timeout to fetchCompatibleModelIds and skip upstream connections (#541)

The fetchCompatibleModelIds() function had no timeout on its fetch() call,
causing /v1/models to hang indefinitely when an openai-compatible provider
was unreachable or slow to respond.

Additionally, upstream/cross-instance connections (provider IDs containing
a UUID suffix like openai-compatible-chat-XXXXXXXX) would trigger recursive
/models fetches between instances, creating infinite loops.

Fixes:
- Add AbortController with 5-second timeout to the fetch() call
- Skip dynamic model fetching for upstream/cross-instance connections
  (detected by UUID suffix pattern in provider ID)
- Existing try/catch already handles abort errors gracefully

Co-authored-by: Agent Zero <agent@agent-zero.local>
This commit is contained in:
Omar Nahhas Sanchez
2026-04-10 06:30:07 +03:00
committed by GitHub
parent 878cdf302b
commit 838d9a7a04

View File

@@ -7,6 +7,9 @@ const parseOpenAIStyleModels = (data) => {
return data?.data || data?.models || data?.results || []; return data?.data || data?.models || data?.results || [];
}; };
// Matches provider IDs that are upstream/cross-instance connections (contain a UUID suffix)
const UPSTREAM_CONNECTION_RE = /[-_][0-9a-f]{8,}$/i;
async function fetchCompatibleModelIds(connection) { async function fetchCompatibleModelIds(connection) {
if (!connection?.apiKey) return []; if (!connection?.apiKey) return [];
@@ -37,11 +40,15 @@ async function fetchCompatibleModelIds(connection) {
} }
try { try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(url, { const response = await fetch(url, {
method: "GET", method: "GET",
headers, headers,
cache: "no-store", cache: "no-store",
signal: controller.signal,
}); });
clearTimeout(timeoutId);
if (!response.ok) return []; if (!response.ok) return [];
@@ -167,7 +174,7 @@ export async function GET() {
) )
: providerModels.map((model) => model.id); : providerModels.map((model) => model.id);
if (isCompatibleProvider && rawModelIds.length === 0) { if (isCompatibleProvider && rawModelIds.length === 0 && !UPSTREAM_CONNECTION_RE.test(providerId)) {
rawModelIds = await fetchCompatibleModelIds(conn); rawModelIds = await fetchCompatibleModelIds(conn);
} }