setApiConfigurationField("includeMaxTokens", e.target.checked)}>
-
+ onChange={(e) =>
+ setApiConfigurationField("includeMaxTokens", (e.target as HTMLInputElement).checked)
+ }>
+
- Limit the maximum number of tokens in the response
+ {t("settings:limitMaxTokensDescription")}
{apiConfiguration?.includeMaxTokens && (
-
+
setApiConfigurationField("modelMaxTokens", value)}
/>
- {apiConfiguration?.modelMaxTokens || 2048}
+
+ {apiConfiguration?.modelMaxTokens || HUGGINGFACE_DEFAULT_MAX_TOKENS}
+
- Maximum tokens to generate in response
+ {t("settings:maxTokensGenerateDescription")}
diff --git a/webview-ui/src/components/settings/providers/__tests__/HuggingFace.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/HuggingFace.spec.tsx
index ffbfbc7dcb9..0256fe94d35 100644
--- a/webview-ui/src/components/settings/providers/__tests__/HuggingFace.spec.tsx
+++ b/webview-ui/src/components/settings/providers/__tests__/HuggingFace.spec.tsx
@@ -64,6 +64,10 @@ vi.mock("@src/i18n/TranslationContext", () => ({
"settings:providers.getHuggingFaceApiKey": "Get Hugging Face API Key",
"settings:providers.huggingFaceApiKey": "Hugging Face API Key",
"settings:providers.huggingFaceModelId": "Model ID",
+ "settings:modelInfo.fetchingModels": "Fetching models...",
+ "settings:modelInfo.errorFetchingModels": "Error fetching models",
+ "settings:modelInfo.noModelsFound": "No models found",
+ "settings:modelInfo.noImages": "Does not support images",
}
return translations[key] || key
},
@@ -90,11 +94,31 @@ vi.mock("@src/components/ui", () => ({
),
}))
+// Mock the formatPrice utility
+vi.mock("@/utils/formatPrice", () => ({
+ formatPrice: (price: number) => `$${price.toFixed(2)}`,
+}))
+
+// Create a mock postMessage function
+const mockPostMessage = vi.fn()
+
+// Mock the vscode module
+vi.mock("@src/utils/vscode", () => ({
+ vscode: {
+ postMessage: vi.fn(),
+ },
+}))
+
+// Import the mocked module to set up the spy
+import { vscode } from "@src/utils/vscode"
+
describe("HuggingFace Component", () => {
const mockSetApiConfigurationField = vi.fn()
beforeEach(() => {
vi.clearAllMocks()
+ // Set up the mock implementation
+ vi.mocked(vscode.postMessage).mockImplementation(mockPostMessage)
})
it("should render with internationalized labels", () => {
@@ -170,4 +194,102 @@ describe("HuggingFace Component", () => {
expect(apiKeyButton).toBeInTheDocument()
expect(apiKeyButton).toHaveTextContent("Get Hugging Face API Key")
})
+
+ it("should fetch models when component mounts", () => {
+ const apiConfiguration: Partial
= {
+ huggingFaceApiKey: "test-api-key",
+ huggingFaceModelId: "",
+ }
+
+ render(
+ ,
+ )
+
+ // Check that the fetch models message was sent
+ expect(mockPostMessage).toHaveBeenCalledWith({
+ type: "requestHuggingFaceModels",
+ })
+ })
+
+ it("should display loading state while fetching models", () => {
+ const apiConfiguration: Partial = {
+ huggingFaceApiKey: "test-api-key",
+ huggingFaceModelId: "",
+ }
+
+ render(
+ ,
+ )
+
+ // Check for loading text in the label
+ expect(screen.getByText("settings:providers.huggingFaceLoading")).toBeInTheDocument()
+ })
+
+ it("should display model capabilities when a model is selected", async () => {
+ const apiConfiguration: Partial = {
+ huggingFaceApiKey: "test-api-key",
+ huggingFaceModelId: "test-model",
+ huggingFaceInferenceProvider: "test-provider", // Select a specific provider to show pricing
+ }
+
+ const { rerender } = render(
+ ,
+ )
+
+ // Simulate receiving models from the backend
+ const mockModels = [
+ {
+ id: "test-model",
+ object: "model",
+ created: Date.now(),
+ owned_by: "test",
+ providers: [
+ {
+ provider: "test-provider",
+ status: "live" as const,
+ supports_tools: false,
+ supports_structured_output: false,
+ context_length: 8192,
+ pricing: {
+ input: 0.001,
+ output: 0.002,
+ },
+ },
+ ],
+ },
+ ]
+
+ // Simulate message event
+ const messageEvent = new MessageEvent("message", {
+ data: {
+ type: "huggingFaceModels",
+ huggingFaceModels: mockModels,
+ },
+ })
+ window.dispatchEvent(messageEvent)
+
+ // Re-render to trigger effect
+ rerender(
+ ,
+ )
+
+ // Check that model capabilities are displayed
+ expect(screen.getByText("Does not support images")).toBeInTheDocument()
+ expect(screen.getByText("8,192 tokens")).toBeInTheDocument()
+ // Check that both input and output prices are displayed
+ const priceElements = screen.getAllByText("$0.00 / 1M tokens")
+ expect(priceElements).toHaveLength(2) // One for input, one for output
+ })
})
diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json
index 047b5858bf2..3388e341697 100644
--- a/webview-ui/src/i18n/locales/ca/settings.json
+++ b/webview-ui/src/i18n/locales/ca/settings.json
@@ -754,5 +754,8 @@
"useCustomArn": "Utilitza ARN personalitzat..."
},
"includeMaxOutputTokens": "Incloure tokens màxims de sortida",
- "includeMaxOutputTokensDescription": "Enviar el paràmetre de tokens màxims de sortida a les sol·licituds API. Alguns proveïdors poden no admetre això."
+ "includeMaxOutputTokensDescription": "Enviar el paràmetre de tokens màxims de sortida a les sol·licituds API. Alguns proveïdors poden no admetre això.",
+ "limitMaxTokensDescription": "Limitar el nombre màxim de tokens en la resposta",
+ "maxOutputTokensLabel": "Tokens màxims de sortida",
+ "maxTokensGenerateDescription": "Tokens màxims a generar en la resposta"
}
diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json
index fa646854628..c1c8ea5460f 100644
--- a/webview-ui/src/i18n/locales/de/settings.json
+++ b/webview-ui/src/i18n/locales/de/settings.json
@@ -754,5 +754,8 @@
"useCustomArn": "Benutzerdefinierte ARN verwenden..."
},
"includeMaxOutputTokens": "Maximale Ausgabe-Tokens einbeziehen",
- "includeMaxOutputTokensDescription": "Senden Sie den Parameter für maximale Ausgabe-Tokens in API-Anfragen. Einige Anbieter unterstützen dies möglicherweise nicht."
+ "includeMaxOutputTokensDescription": "Senden Sie den Parameter für maximale Ausgabe-Tokens in API-Anfragen. Einige Anbieter unterstützen dies möglicherweise nicht.",
+ "limitMaxTokensDescription": "Begrenze die maximale Anzahl von Tokens in der Antwort",
+ "maxOutputTokensLabel": "Maximale Ausgabe-Tokens",
+ "maxTokensGenerateDescription": "Maximale Tokens, die in der Antwort generiert werden"
}
diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json
index f2b05b33691..51a1b335289 100644
--- a/webview-ui/src/i18n/locales/en/settings.json
+++ b/webview-ui/src/i18n/locales/en/settings.json
@@ -754,5 +754,8 @@
"useCustomArn": "Use custom ARN..."
},
"includeMaxOutputTokens": "Include max output tokens",
- "includeMaxOutputTokensDescription": "Send max output tokens parameter in API requests. Some providers may not support this."
+ "includeMaxOutputTokensDescription": "Send max output tokens parameter in API requests. Some providers may not support this.",
+ "limitMaxTokensDescription": "Limit the maximum number of tokens in the response",
+ "maxOutputTokensLabel": "Max output tokens",
+ "maxTokensGenerateDescription": "Maximum tokens to generate in response"
}
diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json
index 3d60bfb45c3..f422169322c 100644
--- a/webview-ui/src/i18n/locales/es/settings.json
+++ b/webview-ui/src/i18n/locales/es/settings.json
@@ -754,5 +754,8 @@
"useCustomArn": "Usar ARN personalizado..."
},
"includeMaxOutputTokens": "Incluir tokens máximos de salida",
- "includeMaxOutputTokensDescription": "Enviar parámetro de tokens máximos de salida en solicitudes API. Algunos proveedores pueden no soportar esto."
+ "includeMaxOutputTokensDescription": "Enviar parámetro de tokens máximos de salida en solicitudes API. Algunos proveedores pueden no soportar esto.",
+ "limitMaxTokensDescription": "Limitar el número máximo de tokens en la respuesta",
+ "maxOutputTokensLabel": "Tokens máximos de salida",
+ "maxTokensGenerateDescription": "Tokens máximos a generar en la respuesta"
}
diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json
index 2654afcbdc6..dce37331b72 100644
--- a/webview-ui/src/i18n/locales/fr/settings.json
+++ b/webview-ui/src/i18n/locales/fr/settings.json
@@ -754,5 +754,8 @@
"useCustomArn": "Utiliser un ARN personnalisé..."
},
"includeMaxOutputTokens": "Inclure les tokens de sortie maximum",
- "includeMaxOutputTokensDescription": "Envoyer le paramètre de tokens de sortie maximum dans les requêtes API. Certains fournisseurs peuvent ne pas supporter cela."
+ "includeMaxOutputTokensDescription": "Envoyer le paramètre de tokens de sortie maximum dans les requêtes API. Certains fournisseurs peuvent ne pas supporter cela.",
+ "limitMaxTokensDescription": "Limiter le nombre maximum de tokens dans la réponse",
+ "maxOutputTokensLabel": "Tokens de sortie maximum",
+ "maxTokensGenerateDescription": "Tokens maximum à générer dans la réponse"
}
diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json
index 279de29ada2..8d15b258ef7 100644
--- a/webview-ui/src/i18n/locales/hi/settings.json
+++ b/webview-ui/src/i18n/locales/hi/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "कस्टम ARN का उपयोग करें..."
},
"includeMaxOutputTokens": "अधिकतम आउटपुट टोकन शामिल करें",
- "includeMaxOutputTokensDescription": "API अनुरोधों में अधिकतम आउटपुट टोकन पैरामीटर भेजें। कुछ प्रदाता इसका समर्थन नहीं कर सकते हैं।"
+ "includeMaxOutputTokensDescription": "API अनुरोधों में अधिकतम आउटपुट टोकन पैरामीटर भेजें। कुछ प्रदाता इसका समर्थन नहीं कर सकते हैं।",
+ "limitMaxTokensDescription": "प्रतिक्रिया में टोकन की अधिकतम संख्या सीमित करें",
+ "maxOutputTokensLabel": "अधिकतम आउटपुट टोकन",
+ "maxTokensGenerateDescription": "प्रतिक्रिया में उत्पन्न करने के लिए अधिकतम टोकन"
}
diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json
index d54db7122ed..9d7d3595abd 100644
--- a/webview-ui/src/i18n/locales/id/settings.json
+++ b/webview-ui/src/i18n/locales/id/settings.json
@@ -784,5 +784,8 @@
"useCustomArn": "Gunakan ARN kustom..."
},
"includeMaxOutputTokens": "Sertakan token output maksimum",
- "includeMaxOutputTokensDescription": "Kirim parameter token output maksimum dalam permintaan API. Beberapa provider mungkin tidak mendukung ini."
+ "includeMaxOutputTokensDescription": "Kirim parameter token output maksimum dalam permintaan API. Beberapa provider mungkin tidak mendukung ini.",
+ "limitMaxTokensDescription": "Batasi jumlah maksimum token dalam respons",
+ "maxOutputTokensLabel": "Token output maksimum",
+ "maxTokensGenerateDescription": "Token maksimum untuk dihasilkan dalam respons"
}
diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json
index ed77701914e..13a5b258acc 100644
--- a/webview-ui/src/i18n/locales/it/settings.json
+++ b/webview-ui/src/i18n/locales/it/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "Usa ARN personalizzato..."
},
"includeMaxOutputTokens": "Includi token di output massimi",
- "includeMaxOutputTokensDescription": "Invia il parametro dei token di output massimi nelle richieste API. Alcuni provider potrebbero non supportarlo."
+ "includeMaxOutputTokensDescription": "Invia il parametro dei token di output massimi nelle richieste API. Alcuni provider potrebbero non supportarlo.",
+ "limitMaxTokensDescription": "Limita il numero massimo di token nella risposta",
+ "maxOutputTokensLabel": "Token di output massimi",
+ "maxTokensGenerateDescription": "Token massimi da generare nella risposta"
}
diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json
index efa020b320f..741aec350fe 100644
--- a/webview-ui/src/i18n/locales/ja/settings.json
+++ b/webview-ui/src/i18n/locales/ja/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "カスタム ARN を使用..."
},
"includeMaxOutputTokens": "最大出力トークンを含める",
- "includeMaxOutputTokensDescription": "APIリクエストで最大出力トークンパラメータを送信します。一部のプロバイダーはこれをサポートしていない場合があります。"
+ "includeMaxOutputTokensDescription": "APIリクエストで最大出力トークンパラメータを送信します。一部のプロバイダーはこれをサポートしていない場合があります。",
+ "limitMaxTokensDescription": "レスポンスの最大トークン数を制限する",
+ "maxOutputTokensLabel": "最大出力トークン",
+ "maxTokensGenerateDescription": "レスポンスで生成する最大トークン数"
}
diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json
index 39b8fd6e333..83f7c714de8 100644
--- a/webview-ui/src/i18n/locales/ko/settings.json
+++ b/webview-ui/src/i18n/locales/ko/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "사용자 지정 ARN 사용..."
},
"includeMaxOutputTokens": "최대 출력 토큰 포함",
- "includeMaxOutputTokensDescription": "API 요청에서 최대 출력 토큰 매개변수를 전송합니다. 일부 제공업체는 이를 지원하지 않을 수 있습니다."
+ "includeMaxOutputTokensDescription": "API 요청에서 최대 출력 토큰 매개변수를 전송합니다. 일부 제공업체는 이를 지원하지 않을 수 있습니다.",
+ "limitMaxTokensDescription": "응답에서 최대 토큰 수 제한",
+ "maxOutputTokensLabel": "최대 출력 토큰",
+ "maxTokensGenerateDescription": "응답에서 생성할 최대 토큰 수"
}
diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json
index d7eba61045e..8e518012068 100644
--- a/webview-ui/src/i18n/locales/nl/settings.json
+++ b/webview-ui/src/i18n/locales/nl/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "Aangepaste ARN gebruiken..."
},
"includeMaxOutputTokens": "Maximale output tokens opnemen",
- "includeMaxOutputTokensDescription": "Stuur maximale output tokens parameter in API-verzoeken. Sommige providers ondersteunen dit mogelijk niet."
+ "includeMaxOutputTokensDescription": "Stuur maximale output tokens parameter in API-verzoeken. Sommige providers ondersteunen dit mogelijk niet.",
+ "limitMaxTokensDescription": "Beperk het maximale aantal tokens in het antwoord",
+ "maxOutputTokensLabel": "Maximale output tokens",
+ "maxTokensGenerateDescription": "Maximale tokens om te genereren in het antwoord"
}
diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json
index 960c59724b8..2cfa5dc4bac 100644
--- a/webview-ui/src/i18n/locales/pl/settings.json
+++ b/webview-ui/src/i18n/locales/pl/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "Użyj niestandardowego ARN..."
},
"includeMaxOutputTokens": "Uwzględnij maksymalne tokeny wyjściowe",
- "includeMaxOutputTokensDescription": "Wyślij parametr maksymalnych tokenów wyjściowych w żądaniach API. Niektórzy dostawcy mogą tego nie obsługiwać."
+ "includeMaxOutputTokensDescription": "Wyślij parametr maksymalnych tokenów wyjściowych w żądaniach API. Niektórzy dostawcy mogą tego nie obsługiwać.",
+ "limitMaxTokensDescription": "Ogranicz maksymalną liczbę tokenów w odpowiedzi",
+ "maxOutputTokensLabel": "Maksymalne tokeny wyjściowe",
+ "maxTokensGenerateDescription": "Maksymalne tokeny do wygenerowania w odpowiedzi"
}
diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json
index 2bb9d4b9213..562ab777b4c 100644
--- a/webview-ui/src/i18n/locales/pt-BR/settings.json
+++ b/webview-ui/src/i18n/locales/pt-BR/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "Usar ARN personalizado..."
},
"includeMaxOutputTokens": "Incluir tokens máximos de saída",
- "includeMaxOutputTokensDescription": "Enviar parâmetro de tokens máximos de saída nas solicitações de API. Alguns provedores podem não suportar isso."
+ "includeMaxOutputTokensDescription": "Enviar parâmetro de tokens máximos de saída nas solicitações de API. Alguns provedores podem não suportar isso.",
+ "limitMaxTokensDescription": "Limitar o número máximo de tokens na resposta",
+ "maxOutputTokensLabel": "Tokens máximos de saída",
+ "maxTokensGenerateDescription": "Tokens máximos para gerar na resposta"
}
diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json
index c57a8db3d6b..0feed462bf7 100644
--- a/webview-ui/src/i18n/locales/ru/settings.json
+++ b/webview-ui/src/i18n/locales/ru/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "Использовать пользовательский ARN..."
},
"includeMaxOutputTokens": "Включить максимальные выходные токены",
- "includeMaxOutputTokensDescription": "Отправлять параметр максимальных выходных токенов в API-запросах. Некоторые провайдеры могут не поддерживать это."
+ "includeMaxOutputTokensDescription": "Отправлять параметр максимальных выходных токенов в API-запросах. Некоторые провайдеры могут не поддерживать это.",
+ "limitMaxTokensDescription": "Ограничить максимальное количество токенов в ответе",
+ "maxOutputTokensLabel": "Максимальные выходные токены",
+ "maxTokensGenerateDescription": "Максимальные токены для генерации в ответе"
}
diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json
index 576e3c1b538..20917bdde64 100644
--- a/webview-ui/src/i18n/locales/tr/settings.json
+++ b/webview-ui/src/i18n/locales/tr/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "Özel ARN kullan..."
},
"includeMaxOutputTokens": "Maksimum çıktı tokenlerini dahil et",
- "includeMaxOutputTokensDescription": "API isteklerinde maksimum çıktı token parametresini gönder. Bazı sağlayıcılar bunu desteklemeyebilir."
+ "includeMaxOutputTokensDescription": "API isteklerinde maksimum çıktı token parametresini gönder. Bazı sağlayıcılar bunu desteklemeyebilir.",
+ "limitMaxTokensDescription": "Yanıttaki maksimum token sayısını sınırla",
+ "maxOutputTokensLabel": "Maksimum çıktı tokenları",
+ "maxTokensGenerateDescription": "Yanıtta oluşturulacak maksimum token sayısı"
}
diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json
index 76a4f9397d6..c30830741e2 100644
--- a/webview-ui/src/i18n/locales/vi/settings.json
+++ b/webview-ui/src/i18n/locales/vi/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "Sử dụng ARN tùy chỉnh..."
},
"includeMaxOutputTokens": "Bao gồm token đầu ra tối đa",
- "includeMaxOutputTokensDescription": "Gửi tham số token đầu ra tối đa trong các yêu cầu API. Một số nhà cung cấp có thể không hỗ trợ điều này."
+ "includeMaxOutputTokensDescription": "Gửi tham số token đầu ra tối đa trong các yêu cầu API. Một số nhà cung cấp có thể không hỗ trợ điều này.",
+ "limitMaxTokensDescription": "Giới hạn số lượng token tối đa trong phản hồi",
+ "maxOutputTokensLabel": "Token đầu ra tối đa",
+ "maxTokensGenerateDescription": "Token tối đa để tạo trong phản hồi"
}
diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json
index 748b9f1d5dc..d6c7e0580d5 100644
--- a/webview-ui/src/i18n/locales/zh-CN/settings.json
+++ b/webview-ui/src/i18n/locales/zh-CN/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "使用自定义 ARN..."
},
"includeMaxOutputTokens": "包含最大输出 Token 数",
- "includeMaxOutputTokensDescription": "在 API 请求中发送最大输出 Token 参数。某些提供商可能不支持此功能。"
+ "includeMaxOutputTokensDescription": "在 API 请求中发送最大输出 Token 参数。某些提供商可能不支持此功能。",
+ "limitMaxTokensDescription": "限制响应中的最大 Token 数量",
+ "maxOutputTokensLabel": "最大输出 Token 数",
+ "maxTokensGenerateDescription": "响应中生成的最大 Token 数"
}
diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json
index f4a6149102e..07b94a387fe 100644
--- a/webview-ui/src/i18n/locales/zh-TW/settings.json
+++ b/webview-ui/src/i18n/locales/zh-TW/settings.json
@@ -755,5 +755,8 @@
"useCustomArn": "使用自訂 ARN..."
},
"includeMaxOutputTokens": "包含最大輸出 Token 數",
- "includeMaxOutputTokensDescription": "在 API 請求中傳送最大輸出 Token 參數。某些提供商可能不支援此功能。"
+ "includeMaxOutputTokensDescription": "在 API 請求中傳送最大輸出 Token 參數。某些提供商可能不支援此功能。",
+ "limitMaxTokensDescription": "限制回應中的最大 Token 數量",
+ "maxOutputTokensLabel": "最大輸出 Token 數",
+ "maxTokensGenerateDescription": "回應中產生的最大 Token 數"
}
From 3201a430c41ee62c7dd6f3b4931e6bfbe7737ef0 Mon Sep 17 00:00:00 2001
From: Daniel Riccio
Date: Fri, 25 Jul 2025 18:56:17 -0500
Subject: [PATCH 5/5] fix: preserve HuggingFace provider details in model
response
- Store raw HuggingFace models in cache to preserve provider information
- Export getCachedRawHuggingFaceModels to retrieve full model data
- Update huggingface-models.ts to return cached raw models when available
- Include provider name in model descriptions
- Always add provider-specific variants to show all available providers
- Remove console.log statements from fetcher
---
src/api/huggingface-models.ts | 77 ++++++++++++++---------
src/api/providers/fetchers/huggingface.ts | 27 ++++----
2 files changed, 64 insertions(+), 40 deletions(-)
diff --git a/src/api/huggingface-models.ts b/src/api/huggingface-models.ts
index e064575d6a3..1ee6369d4bc 100644
--- a/src/api/huggingface-models.ts
+++ b/src/api/huggingface-models.ts
@@ -1,5 +1,10 @@
-import { getHuggingFaceModels as fetchModels, type HuggingFaceModel } from "./providers/fetchers/huggingface"
-import type { ModelRecord } from "../shared/api"
+import {
+ getHuggingFaceModels as fetchModels,
+ getCachedRawHuggingFaceModels,
+ type HuggingFaceModel,
+} from "./providers/fetchers/huggingface"
+import axios from "axios"
+import { HUGGINGFACE_API_URL } from "@roo-code/types"
export interface HuggingFaceModelsResponse {
models: HuggingFaceModel[]
@@ -8,35 +13,49 @@ export interface HuggingFaceModelsResponse {
}
export async function getHuggingFaceModels(): Promise {
- // Fetch models as ModelRecord
- const modelRecord = await fetchModels()
+ try {
+ // First, trigger the fetch to populate cache
+ await fetchModels()
- // Convert ModelRecord to array of HuggingFaceModel for backward compatibility
- // Note: This is a temporary solution to maintain API compatibility
- const models: HuggingFaceModel[] = Object.entries(modelRecord).map(([id, info]) => ({
- id,
- object: "model" as const,
- created: Date.now(),
- owned_by: "huggingface",
- providers: [
- {
- provider: "auto",
- status: "live" as const,
- context_length: info.contextWindow,
- pricing:
- info.inputPrice && info.outputPrice
- ? {
- input: info.inputPrice,
- output: info.outputPrice,
- }
- : undefined,
+ // Get the raw models from cache
+ const cachedRawModels = getCachedRawHuggingFaceModels()
+
+ if (cachedRawModels) {
+ return {
+ models: cachedRawModels,
+ cached: true,
+ timestamp: Date.now(),
+ }
+ }
+
+ // If no cached raw models, fetch directly from API
+ const response = await axios.get(HUGGINGFACE_API_URL, {
+ headers: {
+ "Upgrade-Insecure-Requests": "1",
+ "Sec-Fetch-Dest": "document",
+ "Sec-Fetch-Mode": "navigate",
+ "Sec-Fetch-Site": "none",
+ "Sec-Fetch-User": "?1",
+ Priority: "u=0, i",
+ Pragma: "no-cache",
+ "Cache-Control": "no-cache",
},
- ],
- }))
+ timeout: 10000,
+ })
+
+ const models = response.data?.data || []
- return {
- models,
- cached: false,
- timestamp: Date.now(),
+ return {
+ models,
+ cached: false,
+ timestamp: Date.now(),
+ }
+ } catch (error) {
+ console.error("Failed to get HuggingFace models:", error)
+ return {
+ models: [],
+ cached: false,
+ timestamp: Date.now(),
+ }
}
}
diff --git a/src/api/providers/fetchers/huggingface.ts b/src/api/providers/fetchers/huggingface.ts
index fead26ce5b5..16c33b9e047 100644
--- a/src/api/providers/fetchers/huggingface.ts
+++ b/src/api/providers/fetchers/huggingface.ts
@@ -80,6 +80,7 @@ type HuggingFaceApiResponse = z.infer
*/
interface CacheEntry {
data: ModelRecord
+ rawModels?: HuggingFaceModel[]
timestamp: number
}
@@ -100,6 +101,9 @@ function parseHuggingFaceModel(model: HuggingFaceModel, provider?: HuggingFacePr
const pricing = provider?.pricing || model.providers.find((p) => p.pricing)?.pricing
+ // Include provider name in description if specific provider is given
+ const description = provider ? `${model.id} via ${provider.provider}` : `${model.id} via HuggingFace`
+
return {
maxTokens: Math.min(contextLength, HUGGINGFACE_DEFAULT_MAX_TOKENS),
contextWindow: contextLength,
@@ -108,7 +112,7 @@ function parseHuggingFaceModel(model: HuggingFaceModel, provider?: HuggingFacePr
supportsComputerUse: false,
inputPrice: pricing?.input,
outputPrice: pricing?.output,
- description: `${model.id} via HuggingFace`,
+ description,
}
}
@@ -123,15 +127,12 @@ export async function getHuggingFaceModels(): Promise {
// Check cache
if (cache && now - cache.timestamp < HUGGINGFACE_CACHE_DURATION) {
- console.log("Using cached HuggingFace models")
return cache.data
}
const models: ModelRecord = {}
try {
- console.log("Fetching HuggingFace models from API...")
-
const response = await axios.get(HUGGINGFACE_API_URL, {
headers: {
"Upgrade-Insecure-Requests": "1",
@@ -159,16 +160,14 @@ export async function getHuggingFaceModels(): Promise {
// Add the base model
models[model.id] = parseHuggingFaceModel(model)
- // Add provider-specific variants if they have different capabilities
+ // Add provider-specific variants for all live providers
for (const provider of model.providers) {
if (provider.status === "live") {
const providerKey = `${model.id}:${provider.provider}`
const providerModel = parseHuggingFaceModel(model, provider)
- // Only add provider variant if it differs from base model
- if (JSON.stringify(models[model.id]) !== JSON.stringify(providerModel)) {
- models[providerKey] = providerModel
- }
+ // Always add provider variants to show all available providers
+ models[providerKey] = providerModel
}
}
}
@@ -176,17 +175,16 @@ export async function getHuggingFaceModels(): Promise {
// Update cache
cache = {
data: models,
+ rawModels: validModels,
timestamp: now,
}
- console.log(`Fetched ${Object.keys(models).length} HuggingFace models`)
return models
} catch (error) {
console.error("Error fetching HuggingFace models:", error)
// Return cached data if available
if (cache) {
- console.log("Using stale cached data due to fetch error")
return cache.data
}
@@ -216,6 +214,13 @@ export function getCachedHuggingFaceModels(): ModelRecord | null {
return cache?.data || null
}
+/**
+ * Get cached raw models for UI display
+ */
+export function getCachedRawHuggingFaceModels(): HuggingFaceModel[] | null {
+ return cache?.rawModels || null
+}
+
/**
* Clear the cache
*/