Add support for Vercel embeddings (#7445)

Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>
This commit is contained in:
Matt Rubens 2025-08-27 13:30:19 -04:00 committed by GitHub
parent 33a8573b02
commit 1ad2129964
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 539 additions and 7 deletions

View file

@ -21,7 +21,9 @@ export const CODEBASE_INDEX_DEFAULTS = {
export const codebaseIndexConfigSchema = z.object({
codebaseIndexEnabled: z.boolean().optional(),
codebaseIndexQdrantUrl: z.string().optional(),
codebaseIndexEmbedderProvider: z.enum(["openai", "ollama", "openai-compatible", "gemini", "mistral"]).optional(),
codebaseIndexEmbedderProvider: z
.enum(["openai", "ollama", "openai-compatible", "gemini", "mistral", "vercel-ai-gateway"])
.optional(),
codebaseIndexEmbedderBaseUrl: z.string().optional(),
codebaseIndexEmbedderModelId: z.string().optional(),
codebaseIndexEmbedderModelDimension: z.number().optional(),
@ -48,6 +50,7 @@ export const codebaseIndexModelsSchema = z.object({
"openai-compatible": z.record(z.string(), z.object({ dimension: z.number() })).optional(),
gemini: z.record(z.string(), z.object({ dimension: z.number() })).optional(),
mistral: z.record(z.string(), z.object({ dimension: z.number() })).optional(),
"vercel-ai-gateway": z.record(z.string(), z.object({ dimension: z.number() })).optional(),
})
export type CodebaseIndexModels = z.infer<typeof codebaseIndexModelsSchema>
@ -64,6 +67,7 @@ export const codebaseIndexProviderSchema = z.object({
codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(),
codebaseIndexGeminiApiKey: z.string().optional(),
codebaseIndexMistralApiKey: z.string().optional(),
codebaseIndexVercelAiGatewayApiKey: z.string().optional(),
})
export type CodebaseIndexProvider = z.infer<typeof codebaseIndexProviderSchema>

View file

@ -192,6 +192,7 @@ export const SECRET_STATE_KEYS = [
"codebaseIndexOpenAiCompatibleApiKey",
"codebaseIndexGeminiApiKey",
"codebaseIndexMistralApiKey",
"codebaseIndexVercelAiGatewayApiKey",
"huggingFaceApiKey",
"sambaNovaApiKey",
"zaiApiKey",

View file

@ -68,7 +68,8 @@ export async function getVercelAiGatewayModels(options?: ApiHandlerOptions): Pro
for (const model of data) {
const { id } = model
// Only include language models
// Only include language models for chat inference
// Embedding models are statically defined in embeddingModels.ts
if (model.type !== "language") {
continue
}

View file

@ -2095,6 +2095,12 @@ export const webviewMessageHandler = async (
settings.codebaseIndexMistralApiKey,
)
}
if (settings.codebaseIndexVercelAiGatewayApiKey !== undefined) {
await provider.contextProxy.storeSecret(
"codebaseIndexVercelAiGatewayApiKey",
settings.codebaseIndexVercelAiGatewayApiKey,
)
}
// Send success response first - settings are saved regardless of validation
await provider.postMessageToWebview({
@ -2229,6 +2235,9 @@ export const webviewMessageHandler = async (
))
const hasGeminiApiKey = !!(await provider.context.secrets.get("codebaseIndexGeminiApiKey"))
const hasMistralApiKey = !!(await provider.context.secrets.get("codebaseIndexMistralApiKey"))
const hasVercelAiGatewayApiKey = !!(await provider.context.secrets.get(
"codebaseIndexVercelAiGatewayApiKey",
))
provider.postMessageToWebview({
type: "codeIndexSecretStatus",
@ -2238,6 +2247,7 @@ export const webviewMessageHandler = async (
hasOpenAiCompatibleApiKey,
hasGeminiApiKey,
hasMistralApiKey,
hasVercelAiGatewayApiKey,
},
})
break

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Falta la configuració compatible amb OpenAI per crear l'embedder",
"geminiConfigMissing": "Falta la configuració de Gemini per crear l'embedder",
"mistralConfigMissing": "Falta la configuració de Mistral per crear l'embedder",
"vercelAiGatewayConfigMissing": "Falta la configuració de Vercel AI Gateway per crear l'embedder",
"invalidEmbedderType": "Tipus d'embedder configurat no vàlid: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "No s'ha pogut determinar la dimensió del vector per al model '{{modelId}}' amb el proveïdor '{{provider}}'. Assegura't que la 'Dimensió d'incrustació' estigui configurada correctament als paràmetres del proveïdor compatible amb OpenAI.",
"vectorDimensionNotDetermined": "No s'ha pogut determinar la dimensió del vector per al model '{{modelId}}' amb el proveïdor '{{provider}}'. Comprova els perfils del model o la configuració.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "OpenAI-kompatible Konfiguration fehlt für die Erstellung des Embedders",
"geminiConfigMissing": "Gemini-Konfiguration fehlt für die Erstellung des Embedders",
"mistralConfigMissing": "Mistral-Konfiguration fehlt für die Erstellung des Embedders",
"vercelAiGatewayConfigMissing": "Vercel AI Gateway-Konfiguration fehlt für die Erstellung des Embedders",
"invalidEmbedderType": "Ungültiger Embedder-Typ konfiguriert: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Konnte die Vektordimension für Modell '{{modelId}}' mit Anbieter '{{provider}}' nicht bestimmen. Stelle sicher, dass die 'Embedding-Dimension' in den OpenAI-kompatiblen Anbietereinstellungen korrekt eingestellt ist.",
"vectorDimensionNotDetermined": "Konnte die Vektordimension für Modell '{{modelId}}' mit Anbieter '{{provider}}' nicht bestimmen. Überprüfe die Modellprofile oder Konfiguration.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "OpenAI Compatible configuration missing for embedder creation",
"geminiConfigMissing": "Gemini configuration missing for embedder creation",
"mistralConfigMissing": "Mistral configuration missing for embedder creation",
"vercelAiGatewayConfigMissing": "Vercel AI Gateway configuration missing for embedder creation",
"invalidEmbedderType": "Invalid embedder type configured: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Could not determine vector dimension for model '{{modelId}}' with provider '{{provider}}'. Please ensure the 'Embedding Dimension' is correctly set in the OpenAI-Compatible provider settings.",
"vectorDimensionNotDetermined": "Could not determine vector dimension for model '{{modelId}}' with provider '{{provider}}'. Check model profiles or configuration.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Falta la configuración compatible con OpenAI para crear el incrustador",
"geminiConfigMissing": "Falta la configuración de Gemini para crear el incrustador",
"mistralConfigMissing": "Falta la configuración de Mistral para la creación del incrustador",
"vercelAiGatewayConfigMissing": "Falta la configuración de Vercel AI Gateway para la creación del incrustador",
"invalidEmbedderType": "Tipo de incrustador configurado inválido: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "No se pudo determinar la dimensión del vector para el modelo '{{modelId}}' con el proveedor '{{provider}}'. Asegúrate de que la 'Dimensión de incrustación' esté configurada correctamente en los ajustes del proveedor compatible con OpenAI.",
"vectorDimensionNotDetermined": "No se pudo determinar la dimensión del vector para el modelo '{{modelId}}' con el proveedor '{{provider}}'. Verifica los perfiles del modelo o la configuración.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Configuration compatible OpenAI manquante pour la création de l'embedder",
"geminiConfigMissing": "Configuration Gemini manquante pour la création de l'embedder",
"mistralConfigMissing": "Configuration Mistral manquante pour la création de l'embedder",
"vercelAiGatewayConfigMissing": "Configuration Vercel AI Gateway manquante pour la création de l'embedder",
"invalidEmbedderType": "Type d'embedder configuré invalide : {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Impossible de déterminer la dimension du vecteur pour le modèle '{{modelId}}' avec le fournisseur '{{provider}}'. Assure-toi que la 'Dimension d'embedding' est correctement définie dans les paramètres du fournisseur compatible OpenAI.",
"vectorDimensionNotDetermined": "Impossible de déterminer la dimension du vecteur pour le modèle '{{modelId}}' avec le fournisseur '{{provider}}'. Vérifie les profils du modèle ou la configuration.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "एम्बेडर बनाने के लिए OpenAI संगत कॉन्फ़िगरेशन गायब है",
"geminiConfigMissing": "एम्बेडर बनाने के लिए Gemini कॉन्फ़िगरेशन गायब है",
"mistralConfigMissing": "एम्बेडर निर्माण के लिए मिस्ट्रल कॉन्फ़िगरेशन गायब है",
"vercelAiGatewayConfigMissing": "एम्बेडर निर्माण के लिए Vercel AI Gateway कॉन्फ़िगरेशन गायब है",
"invalidEmbedderType": "अमान्य एम्बेडर प्रकार कॉन्फ़िगर किया गया: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "प्रदाता '{{provider}}' के साथ मॉडल '{{modelId}}' के लिए वेक्टर आयाम निर्धारित नहीं कर सका। कृपया सुनिश्चित करें कि OpenAI-संगत प्रदाता सेटिंग्स में 'एम्बेडिंग आयाम' सही तरीके से सेट है।",
"vectorDimensionNotDetermined": "प्रदाता '{{provider}}' के साथ मॉडल '{{modelId}}' के लिए वेक्टर आयाम निर्धारित नहीं कर सका। मॉडल प्रोफ़ाइल या कॉन्फ़िगरेशन की जांच करें।",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Konfigurasi yang kompatibel dengan OpenAI tidak ada untuk membuat embedder",
"geminiConfigMissing": "Konfigurasi Gemini tidak ada untuk membuat embedder",
"mistralConfigMissing": "Konfigurasi Mistral hilang untuk pembuatan embedder",
"vercelAiGatewayConfigMissing": "Konfigurasi Vercel AI Gateway hilang untuk pembuatan embedder",
"invalidEmbedderType": "Tipe embedder yang dikonfigurasi tidak valid: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Tidak dapat menentukan dimensi vektor untuk model '{{modelId}}' dengan penyedia '{{provider}}'. Pastikan 'Dimensi Embedding' diatur dengan benar di pengaturan penyedia yang kompatibel dengan OpenAI.",
"vectorDimensionNotDetermined": "Tidak dapat menentukan dimensi vektor untuk model '{{modelId}}' dengan penyedia '{{provider}}'. Periksa profil model atau konfigurasi.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Configurazione compatibile con OpenAI mancante per la creazione dell'embedder",
"geminiConfigMissing": "Configurazione Gemini mancante per la creazione dell'embedder",
"mistralConfigMissing": "Configurazione di Mistral mancante per la creazione dell'embedder",
"vercelAiGatewayConfigMissing": "Configurazione di Vercel AI Gateway mancante per la creazione dell'embedder",
"invalidEmbedderType": "Tipo di embedder configurato non valido: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Impossibile determinare la dimensione del vettore per il modello '{{modelId}}' con il provider '{{provider}}'. Assicurati che la 'Dimensione di embedding' sia impostata correttamente nelle impostazioni del provider compatibile con OpenAI.",
"vectorDimensionNotDetermined": "Impossibile determinare la dimensione del vettore per il modello '{{modelId}}' con il provider '{{provider}}'. Controlla i profili del modello o la configurazione.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "エンベッダー作成のためのOpenAI互換設定がありません",
"geminiConfigMissing": "エンベッダー作成のためのGemini設定がありません",
"mistralConfigMissing": "エンベッダー作成のためのMistral設定がありません",
"vercelAiGatewayConfigMissing": "エンベッダー作成のためのVercel AI Gateway設定がありません",
"invalidEmbedderType": "無効なエンベッダータイプが設定されています: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "プロバイダー '{{provider}}' のモデル '{{modelId}}' の埋め込み次元を決定できませんでした。OpenAI互換プロバイダー設定で「埋め込み次元」が正しく設定されていることを確認してください。",
"vectorDimensionNotDetermined": "プロバイダー '{{provider}}' のモデル '{{modelId}}' の埋め込み次元を決定できませんでした。モデルプロファイルまたは設定を確認してください。",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "임베더 생성을 위한 OpenAI 호환 구성이 누락되었습니다",
"geminiConfigMissing": "임베더 생성을 위한 Gemini 구성이 누락되었습니다",
"mistralConfigMissing": "임베더 생성을 위한 Mistral 구성이 없습니다",
"vercelAiGatewayConfigMissing": "임베더 생성을 위한 Vercel AI Gateway 구성이 없습니다",
"invalidEmbedderType": "잘못된 임베더 유형이 구성되었습니다: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "프로바이더 '{{provider}}'의 모델 '{{modelId}}'에 대한 벡터 차원을 결정할 수 없습니다. OpenAI 호환 프로바이더 설정에서 '임베딩 차원'이 올바르게 설정되어 있는지 확인하세요.",
"vectorDimensionNotDetermined": "프로바이더 '{{provider}}'의 모델 '{{modelId}}'에 대한 벡터 차원을 결정할 수 없습니다. 모델 프로필 또는 구성을 확인하세요.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "OpenAI-compatibele configuratie ontbreekt voor het maken van embedder",
"geminiConfigMissing": "Gemini-configuratie ontbreekt voor het maken van embedder",
"mistralConfigMissing": "Mistral-configuratie ontbreekt voor het maken van de embedder",
"vercelAiGatewayConfigMissing": "Vercel AI Gateway-configuratie ontbreekt voor het maken van de embedder",
"invalidEmbedderType": "Ongeldig embedder-type geconfigureerd: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Kan de vectordimensie voor model '{{modelId}}' met provider '{{provider}}' niet bepalen. Zorg ervoor dat de 'Embedding Dimensie' correct is ingesteld in de OpenAI-compatibele provider-instellingen.",
"vectorDimensionNotDetermined": "Kan de vectordimensie voor model '{{modelId}}' met provider '{{provider}}' niet bepalen. Controleer modelprofielen of configuratie.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Brak konfiguracji kompatybilnej z OpenAI do utworzenia embeddera",
"geminiConfigMissing": "Brak konfiguracji Gemini do utworzenia embeddera",
"mistralConfigMissing": "Brak konfiguracji Mistral do utworzenia embeddera",
"vercelAiGatewayConfigMissing": "Brak konfiguracji Vercel AI Gateway do utworzenia embeddera",
"invalidEmbedderType": "Skonfigurowano nieprawidłowy typ embeddera: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Nie można określić wymiaru wektora dla modelu '{{modelId}}' z dostawcą '{{provider}}'. Upewnij się, że 'Wymiar osadzania' jest poprawnie ustawiony w ustawieniach dostawcy kompatybilnego z OpenAI.",
"vectorDimensionNotDetermined": "Nie można określić wymiaru wektora dla modelu '{{modelId}}' z dostawcą '{{provider}}'. Sprawdź profile modelu lub konfigurację.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Configuração compatível com OpenAI ausente para criação do embedder",
"geminiConfigMissing": "Configuração do Gemini ausente para criação do embedder",
"mistralConfigMissing": "Configuração do Mistral ausente para a criação do embedder",
"vercelAiGatewayConfigMissing": "Configuração do Vercel AI Gateway ausente para a criação do embedder",
"invalidEmbedderType": "Tipo de embedder configurado inválido: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Não foi possível determinar a dimensão do vetor para o modelo '{{modelId}}' com o provedor '{{provider}}'. Certifique-se de que a 'Dimensão de Embedding' esteja configurada corretamente nas configurações do provedor compatível com OpenAI.",
"vectorDimensionNotDetermined": "Não foi possível determinar a dimensão do vetor para o modelo '{{modelId}}' com o provedor '{{provider}}'. Verifique os perfis do modelo ou a configuração.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Отсутствует конфигурация, совместимая с OpenAI, для создания эмбеддера",
"geminiConfigMissing": "Отсутствует конфигурация Gemini для создания эмбеддера",
"mistralConfigMissing": "Конфигурация Mistral отсутствует для создания эмбеддера",
"vercelAiGatewayConfigMissing": "Конфигурация Vercel AI Gateway отсутствует для создания эмбеддера",
"invalidEmbedderType": "Настроен недопустимый тип эмбеддера: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Не удалось определить размерность вектора для модели '{{modelId}}' с провайдером '{{provider}}'. Убедитесь, что 'Размерность эмбеддинга' правильно установлена в настройках провайдера, совместимого с OpenAI.",
"vectorDimensionNotDetermined": "Не удалось определить размерность вектора для модели '{{modelId}}' с провайдером '{{provider}}'. Проверьте профили модели или конфигурацию.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Gömücü oluşturmak için OpenAI uyumlu yapılandırması eksik",
"geminiConfigMissing": "Gömücü oluşturmak için Gemini yapılandırması eksik",
"mistralConfigMissing": "Gömücü oluşturmak için Mistral yapılandırması eksik",
"vercelAiGatewayConfigMissing": "Gömücü oluşturmak için Vercel AI Gateway yapılandırması eksik",
"invalidEmbedderType": "Geçersiz gömücü türü yapılandırıldı: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "'{{provider}}' sağlayıcısı ile '{{modelId}}' modeli için vektör boyutu belirlenemedi. OpenAI uyumlu sağlayıcı ayarlarında 'Gömme Boyutu'nun doğru ayarlandığından emin ol.",
"vectorDimensionNotDetermined": "'{{provider}}' sağlayıcısı ile '{{modelId}}' modeli için vektör boyutu belirlenemedi. Model profillerini veya yapılandırmayı kontrol et.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "Thiếu cấu hình tương thích OpenAI để tạo embedder",
"geminiConfigMissing": "Thiếu cấu hình Gemini để tạo embedder",
"mistralConfigMissing": "Thiếu cấu hình Mistral để tạo trình nhúng",
"vercelAiGatewayConfigMissing": "Thiếu cấu hình Vercel AI Gateway để tạo trình nhúng",
"invalidEmbedderType": "Loại embedder được cấu hình không hợp lệ: {{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "Không thể xác định kích thước vector cho mô hình '{{modelId}}' với nhà cung cấp '{{provider}}'. Hãy đảm bảo 'Kích thước Embedding' được cài đặt đúng trong cài đặt nhà cung cấp tương thích OpenAI.",
"vectorDimensionNotDetermined": "Không thể xác định kích thước vector cho mô hình '{{modelId}}' với nhà cung cấp '{{provider}}'. Kiểm tra hồ sơ mô hình hoặc cấu hình.",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "创建嵌入器缺少 OpenAI 兼容配置",
"geminiConfigMissing": "创建嵌入器缺少 Gemini 配置",
"mistralConfigMissing": "创建嵌入器时缺少 Mistral 配置",
"vercelAiGatewayConfigMissing": "创建嵌入器时缺少 Vercel AI Gateway 配置",
"invalidEmbedderType": "配置的嵌入器类型无效:{{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "无法确定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量维度。请确保在 OpenAI 兼容提供商设置中正确设置了「嵌入维度」。",
"vectorDimensionNotDetermined": "无法确定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量维度。请检查模型配置文件或配置。",

View file

@ -47,6 +47,7 @@
"openAiCompatibleConfigMissing": "建立嵌入器缺少 OpenAI 相容設定",
"geminiConfigMissing": "建立嵌入器缺少 Gemini 設定",
"mistralConfigMissing": "建立嵌入器時缺少 Mistral 設定",
"vercelAiGatewayConfigMissing": "建立嵌入器時缺少 Vercel AI Gateway 設定",
"invalidEmbedderType": "設定的嵌入器類型無效:{{embedderProvider}}",
"vectorDimensionNotDeterminedOpenAiCompatible": "無法確定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量維度。請確保在 OpenAI 相容提供商設定中正確設定了「嵌入維度」。",
"vectorDimensionNotDetermined": "無法確定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量維度。請檢查模型設定檔或設定。",

View file

@ -19,6 +19,7 @@ export class CodeIndexConfigManager {
private openAiCompatibleOptions?: { baseUrl: string; apiKey: string }
private geminiOptions?: { apiKey: string }
private mistralOptions?: { apiKey: string }
private vercelAiGatewayOptions?: { apiKey: string }
private qdrantUrl?: string = "http://localhost:6333"
private qdrantApiKey?: string
private searchMinScore?: number
@ -69,6 +70,7 @@ export class CodeIndexConfigManager {
const openAiCompatibleApiKey = this.contextProxy?.getSecret("codebaseIndexOpenAiCompatibleApiKey") ?? ""
const geminiApiKey = this.contextProxy?.getSecret("codebaseIndexGeminiApiKey") ?? ""
const mistralApiKey = this.contextProxy?.getSecret("codebaseIndexMistralApiKey") ?? ""
const vercelAiGatewayApiKey = this.contextProxy?.getSecret("codebaseIndexVercelAiGatewayApiKey") ?? ""
// Update instance variables with configuration
this.codebaseIndexEnabled = codebaseIndexEnabled ?? true
@ -104,6 +106,8 @@ export class CodeIndexConfigManager {
this.embedderProvider = "gemini"
} else if (codebaseIndexEmbedderProvider === "mistral") {
this.embedderProvider = "mistral"
} else if (codebaseIndexEmbedderProvider === "vercel-ai-gateway") {
this.embedderProvider = "vercel-ai-gateway"
} else {
this.embedderProvider = "openai"
}
@ -124,6 +128,7 @@ export class CodeIndexConfigManager {
this.geminiOptions = geminiApiKey ? { apiKey: geminiApiKey } : undefined
this.mistralOptions = mistralApiKey ? { apiKey: mistralApiKey } : undefined
this.vercelAiGatewayOptions = vercelAiGatewayApiKey ? { apiKey: vercelAiGatewayApiKey } : undefined
}
/**
@ -141,6 +146,7 @@ export class CodeIndexConfigManager {
openAiCompatibleOptions?: { baseUrl: string; apiKey: string }
geminiOptions?: { apiKey: string }
mistralOptions?: { apiKey: string }
vercelAiGatewayOptions?: { apiKey: string }
qdrantUrl?: string
qdrantApiKey?: string
searchMinScore?: number
@ -160,6 +166,7 @@ export class CodeIndexConfigManager {
openAiCompatibleApiKey: this.openAiCompatibleOptions?.apiKey ?? "",
geminiApiKey: this.geminiOptions?.apiKey ?? "",
mistralApiKey: this.mistralOptions?.apiKey ?? "",
vercelAiGatewayApiKey: this.vercelAiGatewayOptions?.apiKey ?? "",
qdrantUrl: this.qdrantUrl ?? "",
qdrantApiKey: this.qdrantApiKey ?? "",
}
@ -184,6 +191,7 @@ export class CodeIndexConfigManager {
openAiCompatibleOptions: this.openAiCompatibleOptions,
geminiOptions: this.geminiOptions,
mistralOptions: this.mistralOptions,
vercelAiGatewayOptions: this.vercelAiGatewayOptions,
qdrantUrl: this.qdrantUrl,
qdrantApiKey: this.qdrantApiKey,
searchMinScore: this.currentSearchMinScore,
@ -221,6 +229,11 @@ export class CodeIndexConfigManager {
const qdrantUrl = this.qdrantUrl
const isConfigured = !!(apiKey && qdrantUrl)
return isConfigured
} else if (this.embedderProvider === "vercel-ai-gateway") {
const apiKey = this.vercelAiGatewayOptions?.apiKey
const qdrantUrl = this.qdrantUrl
const isConfigured = !!(apiKey && qdrantUrl)
return isConfigured
}
return false // Should not happen if embedderProvider is always set correctly
}
@ -255,6 +268,7 @@ export class CodeIndexConfigManager {
const prevModelDimension = prev?.modelDimension
const prevGeminiApiKey = prev?.geminiApiKey ?? ""
const prevMistralApiKey = prev?.mistralApiKey ?? ""
const prevVercelAiGatewayApiKey = prev?.vercelAiGatewayApiKey ?? ""
const prevQdrantUrl = prev?.qdrantUrl ?? ""
const prevQdrantApiKey = prev?.qdrantApiKey ?? ""
@ -292,6 +306,7 @@ export class CodeIndexConfigManager {
const currentModelDimension = this.modelDimension
const currentGeminiApiKey = this.geminiOptions?.apiKey ?? ""
const currentMistralApiKey = this.mistralOptions?.apiKey ?? ""
const currentVercelAiGatewayApiKey = this.vercelAiGatewayOptions?.apiKey ?? ""
const currentQdrantUrl = this.qdrantUrl ?? ""
const currentQdrantApiKey = this.qdrantApiKey ?? ""
@ -318,6 +333,10 @@ export class CodeIndexConfigManager {
return true
}
if (prevVercelAiGatewayApiKey !== currentVercelAiGatewayApiKey) {
return true
}
// Check for model dimension changes (generic for all providers)
if (prevModelDimension !== currentModelDimension) {
return true
@ -375,6 +394,7 @@ export class CodeIndexConfigManager {
openAiCompatibleOptions: this.openAiCompatibleOptions,
geminiOptions: this.geminiOptions,
mistralOptions: this.mistralOptions,
vercelAiGatewayOptions: this.vercelAiGatewayOptions,
qdrantUrl: this.qdrantUrl,
qdrantApiKey: this.qdrantApiKey,
searchMinScore: this.currentSearchMinScore,

View file

@ -0,0 +1,176 @@
// npx vitest run src/services/code-index/embedders/__tests__/vercel-ai-gateway.spec.ts
import { describe, it, expect, vi, beforeEach } from "vitest"
import { VercelAiGatewayEmbedder } from "../vercel-ai-gateway"
import { OpenAICompatibleEmbedder } from "../openai-compatible"
// Mock the OpenAICompatibleEmbedder
vi.mock("../openai-compatible", () => ({
OpenAICompatibleEmbedder: vi.fn(),
}))
// Mock the TelemetryService
vi.mock("@roo-code/telemetry", () => ({
TelemetryService: {
instance: {
captureEvent: vi.fn(),
},
},
}))
const MockedOpenAICompatibleEmbedder = vi.mocked(OpenAICompatibleEmbedder)
describe("VercelAiGatewayEmbedder", () => {
let embedder: VercelAiGatewayEmbedder
let mockOpenAICompatibleEmbedder: any
beforeEach(() => {
vi.clearAllMocks()
mockOpenAICompatibleEmbedder = {
createEmbeddings: vi.fn(),
validateConfiguration: vi.fn(),
}
MockedOpenAICompatibleEmbedder.mockImplementation(() => mockOpenAICompatibleEmbedder)
})
describe("constructor", () => {
it("should create VercelAiGatewayEmbedder with default model", () => {
// Arrange
const apiKey = "test-vercel-api-key"
// Act
embedder = new VercelAiGatewayEmbedder(apiKey)
// Assert
expect(MockedOpenAICompatibleEmbedder).toHaveBeenCalledWith(
"https://ai-gateway.vercel.sh/v1",
apiKey,
"openai/text-embedding-3-large",
8191,
)
})
it("should create VercelAiGatewayEmbedder with custom model", () => {
// Arrange
const apiKey = "test-vercel-api-key"
const modelId = "openai/text-embedding-3-small"
// Act
embedder = new VercelAiGatewayEmbedder(apiKey, modelId)
// Assert
expect(MockedOpenAICompatibleEmbedder).toHaveBeenCalledWith(
"https://ai-gateway.vercel.sh/v1",
apiKey,
"openai/text-embedding-3-small",
8191,
)
})
it("should throw error when API key is missing", () => {
// Act & Assert
expect(() => new VercelAiGatewayEmbedder("")).toThrow("validation.apiKeyRequired")
})
})
describe("createEmbeddings", () => {
beforeEach(() => {
embedder = new VercelAiGatewayEmbedder("test-api-key")
})
it("should delegate to OpenAICompatibleEmbedder with default model", async () => {
// Arrange
const texts = ["test text 1", "test text 2"]
const expectedResponse = {
embeddings: [
[0.1, 0.2],
[0.3, 0.4],
],
}
mockOpenAICompatibleEmbedder.createEmbeddings.mockResolvedValue(expectedResponse)
// Act
const result = await embedder.createEmbeddings(texts)
// Assert
expect(mockOpenAICompatibleEmbedder.createEmbeddings).toHaveBeenCalledWith(
texts,
"openai/text-embedding-3-large",
)
expect(result).toBe(expectedResponse)
})
it("should delegate to OpenAICompatibleEmbedder with custom model", async () => {
// Arrange
const texts = ["test text"]
const customModel = "google/gemini-embedding-001"
const expectedResponse = { embeddings: [[0.1, 0.2, 0.3]] }
mockOpenAICompatibleEmbedder.createEmbeddings.mockResolvedValue(expectedResponse)
// Act
const result = await embedder.createEmbeddings(texts, customModel)
// Assert
expect(mockOpenAICompatibleEmbedder.createEmbeddings).toHaveBeenCalledWith(texts, customModel)
expect(result).toBe(expectedResponse)
})
it("should handle errors from OpenAICompatibleEmbedder", async () => {
// Arrange
const texts = ["test text"]
const error = new Error("API request failed")
mockOpenAICompatibleEmbedder.createEmbeddings.mockRejectedValue(error)
// Act & Assert
await expect(embedder.createEmbeddings(texts)).rejects.toThrow("API request failed")
expect(mockOpenAICompatibleEmbedder.createEmbeddings).toHaveBeenCalledWith(
texts,
"openai/text-embedding-3-large",
)
})
})
describe("validateConfiguration", () => {
beforeEach(() => {
embedder = new VercelAiGatewayEmbedder("test-api-key")
})
it("should delegate to OpenAICompatibleEmbedder", async () => {
// Arrange
const expectedResult = { valid: true }
mockOpenAICompatibleEmbedder.validateConfiguration.mockResolvedValue(expectedResult)
// Act
const result = await embedder.validateConfiguration()
// Assert
expect(mockOpenAICompatibleEmbedder.validateConfiguration).toHaveBeenCalled()
expect(result).toBe(expectedResult)
})
it("should handle validation errors", async () => {
// Arrange
const error = new Error("Validation failed")
mockOpenAICompatibleEmbedder.validateConfiguration.mockRejectedValue(error)
// Act & Assert
await expect(embedder.validateConfiguration()).rejects.toThrow("Validation failed")
expect(mockOpenAICompatibleEmbedder.validateConfiguration).toHaveBeenCalled()
})
})
describe("embedderInfo", () => {
it("should return correct embedder info", () => {
// Arrange
embedder = new VercelAiGatewayEmbedder("test-api-key")
// Act
const info = embedder.embedderInfo
// Assert
expect(info).toEqual({
name: "vercel-ai-gateway",
})
})
})
})

View file

@ -0,0 +1,100 @@
import { OpenAICompatibleEmbedder } from "./openai-compatible"
import { IEmbedder, EmbeddingResponse, EmbedderInfo } from "../interfaces/embedder"
import { MAX_ITEM_TOKENS } from "../constants"
import { t } from "../../../i18n"
import { TelemetryEventName } from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
/**
* Vercel AI Gateway embedder implementation that wraps the OpenAI Compatible embedder
* with configuration for Vercel AI Gateway's embedding API.
*
* Supported models:
* - openai/text-embedding-3-small (dimension: 1536)
* - openai/text-embedding-3-large (dimension: 3072)
* - openai/text-embedding-ada-002 (dimension: 1536)
* - cohere/embed-v4.0 (dimension: 1024)
* - google/gemini-embedding-001 (dimension: 768)
* - google/text-embedding-005 (dimension: 768)
* - google/text-multilingual-embedding-002 (dimension: 768)
* - amazon/titan-embed-text-v2 (dimension: 1024)
* - mistral/codestral-embed (dimension: 1536)
* - mistral/mistral-embed (dimension: 1024)
*/
export class VercelAiGatewayEmbedder implements IEmbedder {
private readonly openAICompatibleEmbedder: OpenAICompatibleEmbedder
private static readonly VERCEL_AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh/v1"
private static readonly DEFAULT_MODEL = "openai/text-embedding-3-large"
private readonly modelId: string
/**
* Creates a new Vercel AI Gateway embedder
* @param apiKey The Vercel AI Gateway API key for authentication
* @param modelId The model ID to use (defaults to mistral/codestral-embed)
*/
constructor(apiKey: string, modelId?: string) {
if (!apiKey) {
throw new Error(t("embeddings:validation.apiKeyRequired"))
}
// Use provided model or default
this.modelId = modelId || VercelAiGatewayEmbedder.DEFAULT_MODEL
// Create an OpenAI Compatible embedder with Vercel AI Gateway's configuration
this.openAICompatibleEmbedder = new OpenAICompatibleEmbedder(
VercelAiGatewayEmbedder.VERCEL_AI_GATEWAY_BASE_URL,
apiKey,
this.modelId,
MAX_ITEM_TOKENS,
)
}
/**
* Creates embeddings for the given texts using Vercel AI Gateway's embedding API
* @param texts Array of text strings to embed
* @param model Optional model identifier (uses constructor model if not provided)
* @returns Promise resolving to embedding response
*/
async createEmbeddings(texts: string[], model?: string): Promise<EmbeddingResponse> {
try {
// Use the provided model or fall back to the instance's model
const modelToUse = model || this.modelId
return await this.openAICompatibleEmbedder.createEmbeddings(texts, modelToUse)
} catch (error) {
TelemetryService.instance.captureEvent(TelemetryEventName.CODE_INDEX_ERROR, {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
location: "VercelAiGatewayEmbedder:createEmbeddings",
})
throw error
}
}
/**
* Validates the Vercel AI Gateway embedder configuration by delegating to the underlying OpenAI-compatible embedder
* @returns Promise resolving to validation result with success status and optional error message
*/
async validateConfiguration(): Promise<{ valid: boolean; error?: string }> {
try {
// Delegate validation to the OpenAI-compatible embedder
// The error messages will be specific to Vercel AI Gateway since we're using Vercel's base URL
return await this.openAICompatibleEmbedder.validateConfiguration()
} catch (error) {
TelemetryService.instance.captureEvent(TelemetryEventName.CODE_INDEX_ERROR, {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
location: "VercelAiGatewayEmbedder:validateConfiguration",
})
throw error
}
}
/**
* Returns information about this embedder
*/
get embedderInfo(): EmbedderInfo {
return {
name: "vercel-ai-gateway",
}
}
}

View file

@ -14,6 +14,7 @@ export interface CodeIndexConfig {
openAiCompatibleOptions?: { baseUrl: string; apiKey: string }
geminiOptions?: { apiKey: string }
mistralOptions?: { apiKey: string }
vercelAiGatewayOptions?: { apiKey: string }
qdrantUrl?: string
qdrantApiKey?: string
searchMinScore?: number
@ -35,6 +36,7 @@ export type PreviousConfigSnapshot = {
openAiCompatibleApiKey?: string
geminiApiKey?: string
mistralApiKey?: string
vercelAiGatewayApiKey?: string
qdrantUrl?: string
qdrantApiKey?: string
}

View file

@ -28,7 +28,7 @@ export interface EmbeddingResponse {
}
}
export type AvailableEmbedders = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral"
export type AvailableEmbedders = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral" | "vercel-ai-gateway"
export interface EmbedderInfo {
name: AvailableEmbedders

View file

@ -70,7 +70,7 @@ export interface ICodeIndexManager {
}
export type IndexingState = "Standby" | "Indexing" | "Indexed" | "Error"
export type EmbedderProvider = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral"
export type EmbedderProvider = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral" | "vercel-ai-gateway"
export interface IndexProgressUpdate {
systemStatus: IndexingState

View file

@ -4,6 +4,7 @@ import { CodeIndexOllamaEmbedder } from "./embedders/ollama"
import { OpenAICompatibleEmbedder } from "./embedders/openai-compatible"
import { GeminiEmbedder } from "./embedders/gemini"
import { MistralEmbedder } from "./embedders/mistral"
import { VercelAiGatewayEmbedder } from "./embedders/vercel-ai-gateway"
import { EmbedderProvider, getDefaultModelId, getModelDimension } from "../../shared/embeddingModels"
import { QdrantVectorStore } from "./vector-store/qdrant-client"
import { codeParser, DirectoryScanner, FileWatcher } from "./processors"
@ -71,6 +72,11 @@ export class CodeIndexServiceFactory {
throw new Error(t("embeddings:serviceFactory.mistralConfigMissing"))
}
return new MistralEmbedder(config.mistralOptions.apiKey, config.modelId)
} else if (provider === "vercel-ai-gateway") {
if (!config.vercelAiGatewayOptions?.apiKey) {
throw new Error(t("embeddings:serviceFactory.vercelAiGatewayConfigMissing"))
}
return new VercelAiGatewayEmbedder(config.vercelAiGatewayOptions.apiKey, config.modelId)
}
throw new Error(

View file

@ -259,7 +259,13 @@ export interface WebviewMessage {
// Global state settings
codebaseIndexEnabled: boolean
codebaseIndexQdrantUrl: string
codebaseIndexEmbedderProvider: "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral"
codebaseIndexEmbedderProvider:
| "openai"
| "ollama"
| "openai-compatible"
| "gemini"
| "mistral"
| "vercel-ai-gateway"
codebaseIndexEmbedderBaseUrl?: string
codebaseIndexEmbedderModelId: string
codebaseIndexEmbedderModelDimension?: number // Generic dimension for all providers
@ -273,6 +279,7 @@ export interface WebviewMessage {
codebaseIndexOpenAiCompatibleApiKey?: string
codebaseIndexGeminiApiKey?: string
codebaseIndexMistralApiKey?: string
codebaseIndexVercelAiGatewayApiKey?: string
}
}

View file

@ -2,7 +2,7 @@
* Defines profiles for different embedding models, including their dimensions.
*/
export type EmbedderProvider = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral" // Add other providers as needed
export type EmbedderProvider = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral" | "vercel-ai-gateway" // Add other providers as needed
export interface EmbeddingModelProfile {
dimension: number
@ -53,6 +53,23 @@ export const EMBEDDING_MODEL_PROFILES: EmbeddingModelProfiles = {
mistral: {
"codestral-embed-2505": { dimension: 1536, scoreThreshold: 0.4 },
},
"vercel-ai-gateway": {
// OpenAI models
"openai/text-embedding-3-small": { dimension: 1536, scoreThreshold: 0.4 },
"openai/text-embedding-3-large": { dimension: 3072, scoreThreshold: 0.4 },
"openai/text-embedding-ada-002": { dimension: 1536, scoreThreshold: 0.4 },
// Cohere models
"cohere/embed-v4.0": { dimension: 1024, scoreThreshold: 0.4 },
// Google models
"google/gemini-embedding-001": { dimension: 3072, scoreThreshold: 0.4 },
"google/text-embedding-005": { dimension: 768, scoreThreshold: 0.4 },
"google/text-multilingual-embedding-002": { dimension: 768, scoreThreshold: 0.4 },
// Amazon models
"amazon/titan-embed-text-v2": { dimension: 1024, scoreThreshold: 0.4 },
// Mistral models
"mistral/codestral-embed": { dimension: 1536, scoreThreshold: 0.4 },
"mistral/mistral-embed": { dimension: 1024, scoreThreshold: 0.4 },
},
}
/**
@ -143,6 +160,9 @@ export function getDefaultModelId(provider: EmbedderProvider): string {
case "mistral":
return "codestral-embed-2505"
case "vercel-ai-gateway":
return "openai/text-embedding-3-large"
default:
// Fallback for unknown providers
console.warn(`Unknown provider for default model ID: ${provider}. Falling back to OpenAI default.`)

View file

@ -72,6 +72,7 @@ interface LocalCodeIndexSettings {
codebaseIndexOpenAiCompatibleApiKey?: string
codebaseIndexGeminiApiKey?: string
codebaseIndexMistralApiKey?: string
codebaseIndexVercelAiGatewayApiKey?: string
}
// Validation schema for codebase index settings
@ -138,6 +139,16 @@ const createValidationSchema = (provider: EmbedderProvider, t: any) => {
.min(1, t("settings:codeIndex.validation.modelSelectionRequired")),
})
case "vercel-ai-gateway":
return baseSchema.extend({
codebaseIndexVercelAiGatewayApiKey: z
.string()
.min(1, t("settings:codeIndex.validation.vercelAiGatewayApiKeyRequired")),
codebaseIndexEmbedderModelId: z
.string()
.min(1, t("settings:codeIndex.validation.modelSelectionRequired")),
})
default:
return baseSchema
}
@ -182,6 +193,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
codebaseIndexOpenAiCompatibleApiKey: "",
codebaseIndexGeminiApiKey: "",
codebaseIndexMistralApiKey: "",
codebaseIndexVercelAiGatewayApiKey: "",
})
// Initial settings state - stores the settings when popover opens
@ -216,6 +228,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
codebaseIndexOpenAiCompatibleApiKey: "",
codebaseIndexGeminiApiKey: "",
codebaseIndexMistralApiKey: "",
codebaseIndexVercelAiGatewayApiKey: "",
}
setInitialSettings(settings)
setCurrentSettings(settings)
@ -324,6 +337,14 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
if (!prev.codebaseIndexMistralApiKey || prev.codebaseIndexMistralApiKey === SECRET_PLACEHOLDER) {
updated.codebaseIndexMistralApiKey = secretStatus.hasMistralApiKey ? SECRET_PLACEHOLDER : ""
}
if (
!prev.codebaseIndexVercelAiGatewayApiKey ||
prev.codebaseIndexVercelAiGatewayApiKey === SECRET_PLACEHOLDER
) {
updated.codebaseIndexVercelAiGatewayApiKey = secretStatus.hasVercelAiGatewayApiKey
? SECRET_PLACEHOLDER
: ""
}
return updated
}
@ -396,7 +417,8 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
key === "codeIndexOpenAiKey" ||
key === "codebaseIndexOpenAiCompatibleApiKey" ||
key === "codebaseIndexGeminiApiKey" ||
key === "codebaseIndexMistralApiKey"
key === "codebaseIndexMistralApiKey" ||
key === "codebaseIndexVercelAiGatewayApiKey"
) {
dataToValidate[key] = "placeholder-valid"
}
@ -644,6 +666,9 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
<SelectItem value="mistral">
{t("settings:codeIndex.mistralProvider")}
</SelectItem>
<SelectItem value="vercel-ai-gateway">
{t("settings:codeIndex.vercelAiGatewayProvider")}
</SelectItem>
</SelectContent>
</Select>
</div>
@ -1036,6 +1061,76 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
</>
)}
{currentSettings.codebaseIndexEmbedderProvider === "vercel-ai-gateway" && (
<>
<div className="space-y-2">
<label className="text-sm font-medium">
{t("settings:codeIndex.vercelAiGatewayApiKeyLabel")}
</label>
<VSCodeTextField
type="password"
value={currentSettings.codebaseIndexVercelAiGatewayApiKey || ""}
onInput={(e: any) =>
updateSetting(
"codebaseIndexVercelAiGatewayApiKey",
e.target.value,
)
}
placeholder={t(
"settings:codeIndex.vercelAiGatewayApiKeyPlaceholder",
)}
className={cn("w-full", {
"border-red-500": formErrors.codebaseIndexVercelAiGatewayApiKey,
})}
/>
{formErrors.codebaseIndexVercelAiGatewayApiKey && (
<p className="text-xs text-vscode-errorForeground mt-1 mb-0">
{formErrors.codebaseIndexVercelAiGatewayApiKey}
</p>
)}
</div>
<div className="space-y-2">
<label className="text-sm font-medium">
{t("settings:codeIndex.modelLabel")}
</label>
<VSCodeDropdown
value={currentSettings.codebaseIndexEmbedderModelId}
onChange={(e: any) =>
updateSetting("codebaseIndexEmbedderModelId", e.target.value)
}
className={cn("w-full", {
"border-red-500": formErrors.codebaseIndexEmbedderModelId,
})}>
<VSCodeOption value="" className="p-2">
{t("settings:codeIndex.selectModel")}
</VSCodeOption>
{getAvailableModels().map((modelId) => {
const model =
codebaseIndexModels?.[
currentSettings.codebaseIndexEmbedderProvider
]?.[modelId]
return (
<VSCodeOption key={modelId} value={modelId} className="p-2">
{modelId}{" "}
{model
? t("settings:codeIndex.modelDimensions", {
dimension: model.dimension,
})
: ""}
</VSCodeOption>
)
})}
</VSCodeDropdown>
{formErrors.codebaseIndexEmbedderModelId && (
<p className="text-xs text-vscode-errorForeground mt-1 mb-0">
{formErrors.codebaseIndexEmbedderModelId}
</p>
)}
</div>
</>
)}
{/* Qdrant Settings */}
<div className="space-y-2">
<label className="text-sm font-medium">

View file

@ -50,6 +50,9 @@
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Clau de l'API:",
"mistralApiKeyPlaceholder": "Introduïu la vostra clau de l'API de Mistral",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Clau API",
"vercelAiGatewayApiKeyPlaceholder": "Introduïu la vostra clau API de Vercel AI Gateway",
"openaiCompatibleProvider": "Compatible amb OpenAI",
"openAiKeyLabel": "Clau API OpenAI",
"openAiKeyPlaceholder": "Introduïu la vostra clau API OpenAI",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Cal una dimensió de model",
"geminiApiKeyRequired": "Cal una clau d'API de Gemini",
"mistralApiKeyRequired": "La clau de l'API de Mistral és requerida",
"vercelAiGatewayApiKeyRequired": "Es requereix la clau API de Vercel AI Gateway",
"ollamaBaseUrlRequired": "Cal una URL base d'Ollama",
"baseUrlRequired": "Cal una URL base",
"modelDimensionMinValue": "La dimensió del model ha de ser superior a 0"

View file

@ -52,6 +52,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "API-Schlüssel:",
"geminiApiKeyPlaceholder": "Geben Sie Ihren Gemini-API-Schlüssel ein",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API-Schlüssel",
"vercelAiGatewayApiKeyPlaceholder": "Gib deinen Vercel AI Gateway API-Schlüssel ein",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API-Schlüssel:",
"mistralApiKeyPlaceholder": "Gib deinen Mistral-API-Schlüssel ein",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Modellabmessung ist erforderlich",
"geminiApiKeyRequired": "Gemini-API-Schlüssel ist erforderlich",
"mistralApiKeyRequired": "Mistral-API-Schlüssel ist erforderlich",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway API-Schlüssel ist erforderlich",
"ollamaBaseUrlRequired": "Ollama-Basis-URL ist erforderlich",
"baseUrlRequired": "Basis-URL ist erforderlich",
"modelDimensionMinValue": "Modellabmessung muss größer als 0 sein"

View file

@ -55,6 +55,9 @@
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API Key:",
"mistralApiKeyPlaceholder": "Enter your Mistral API key",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API Key",
"vercelAiGatewayApiKeyPlaceholder": "Enter your Vercel AI Gateway API key",
"openaiCompatibleProvider": "OpenAI Compatible",
"openAiKeyLabel": "OpenAI API Key",
"openAiKeyPlaceholder": "Enter your OpenAI API key",
@ -120,6 +123,7 @@
"modelDimensionRequired": "Model dimension is required",
"geminiApiKeyRequired": "Gemini API key is required",
"mistralApiKeyRequired": "Mistral API key is required",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway API key is required",
"ollamaBaseUrlRequired": "Ollama base URL is required",
"baseUrlRequired": "Base URL is required",
"modelDimensionMinValue": "Model dimension must be greater than 0"

View file

@ -52,6 +52,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "Clave API:",
"geminiApiKeyPlaceholder": "Introduce tu clave de API de Gemini",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Clave API",
"vercelAiGatewayApiKeyPlaceholder": "Introduce tu clave API de Vercel AI Gateway",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Clave API:",
"mistralApiKeyPlaceholder": "Introduce tu clave de API de Mistral",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Se requiere la dimensión del modelo",
"geminiApiKeyRequired": "Se requiere la clave API de Gemini",
"mistralApiKeyRequired": "Se requiere la clave de API de Mistral",
"vercelAiGatewayApiKeyRequired": "Se requiere la clave API de Vercel AI Gateway",
"ollamaBaseUrlRequired": "Se requiere la URL base de Ollama",
"baseUrlRequired": "Se requiere la URL base",
"modelDimensionMinValue": "La dimensión del modelo debe ser mayor que 0"

View file

@ -52,6 +52,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "Clé API :",
"geminiApiKeyPlaceholder": "Entrez votre clé API Gemini",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Clé API",
"vercelAiGatewayApiKeyPlaceholder": "Entrez votre clé API Vercel AI Gateway",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Clé d'API:",
"mistralApiKeyPlaceholder": "Entrez votre clé d'API Mistral",
@ -113,6 +116,7 @@
"modelDimensionRequired": "La dimension du modèle est requise",
"geminiApiKeyRequired": "La clé API Gemini est requise",
"mistralApiKeyRequired": "La clé API Mistral est requise",
"vercelAiGatewayApiKeyRequired": "La clé API Vercel AI Gateway est requise",
"ollamaBaseUrlRequired": "L'URL de base Ollama est requise",
"baseUrlRequired": "L'URL de base est requise",
"modelDimensionMinValue": "La dimension du modèle doit être supérieure à 0"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "API कुंजी:",
"geminiApiKeyPlaceholder": "अपना जेमिनी एपीआई कुंजी दर्ज करें",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API कुंजी",
"vercelAiGatewayApiKeyPlaceholder": "अपनी Vercel AI Gateway API कुंजी दर्ज करें",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API कुंजी:",
"mistralApiKeyPlaceholder": "अपनी मिस्ट्रल एपीआई कुंजी दर्ज करें",
@ -113,6 +116,7 @@
"modelDimensionRequired": "मॉडल आयाम आवश्यक है",
"geminiApiKeyRequired": "Gemini API कुंजी आवश्यक है",
"mistralApiKeyRequired": "मिस्ट्रल एपीआई कुंजी आवश्यक है",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway API कुंजी आवश्यक है",
"ollamaBaseUrlRequired": "Ollama आधार URL आवश्यक है",
"baseUrlRequired": "आधार URL आवश्यक है",
"modelDimensionMinValue": "मॉडल आयाम 0 से बड़ा होना चाहिए"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "API Key:",
"geminiApiKeyPlaceholder": "Masukkan kunci API Gemini Anda",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API Key",
"vercelAiGatewayApiKeyPlaceholder": "Masukkan kunci API Vercel AI Gateway Anda",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Kunci API:",
"mistralApiKeyPlaceholder": "Masukkan kunci API Mistral Anda",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Dimensi model diperlukan",
"geminiApiKeyRequired": "Kunci API Gemini diperlukan",
"mistralApiKeyRequired": "Kunci API Mistral diperlukan",
"vercelAiGatewayApiKeyRequired": "Kunci API Vercel AI Gateway diperlukan",
"ollamaBaseUrlRequired": "URL dasar Ollama diperlukan",
"baseUrlRequired": "URL dasar diperlukan",
"modelDimensionMinValue": "Dimensi model harus lebih besar dari 0"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "Chiave API:",
"geminiApiKeyPlaceholder": "Inserisci la tua chiave API Gemini",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Chiave API",
"vercelAiGatewayApiKeyPlaceholder": "Inserisci la tua chiave API Vercel AI Gateway",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Chiave API:",
"mistralApiKeyPlaceholder": "Inserisci la tua chiave API Mistral",
@ -113,6 +116,7 @@
"modelDimensionRequired": "È richiesta la dimensione del modello",
"geminiApiKeyRequired": "È richiesta la chiave API Gemini",
"mistralApiKeyRequired": "La chiave API di Mistral è richiesta",
"vercelAiGatewayApiKeyRequired": "È richiesta la chiave API Vercel AI Gateway",
"ollamaBaseUrlRequired": "È richiesto l'URL di base di Ollama",
"baseUrlRequired": "È richiesto l'URL di base",
"modelDimensionMinValue": "La dimensione del modello deve essere maggiore di 0"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "APIキー",
"geminiApiKeyPlaceholder": "Gemini APIキーを入力してください",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "APIキー",
"vercelAiGatewayApiKeyPlaceholder": "Vercel AI GatewayのAPIキーを入力してください",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "APIキー:",
"mistralApiKeyPlaceholder": "Mistral APIキーを入力してください",
@ -113,6 +116,7 @@
"modelDimensionRequired": "モデルの次元が必要です",
"geminiApiKeyRequired": "Gemini APIキーが必要です",
"mistralApiKeyRequired": "Mistral APIキーが必要です",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway APIキーが必要です",
"ollamaBaseUrlRequired": "OllamaのベースURLが必要です",
"baseUrlRequired": "ベースURLが必要です",
"modelDimensionMinValue": "モデルの次元は0より大きくなければなりません"

View file

@ -50,6 +50,9 @@
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API 키:",
"mistralApiKeyPlaceholder": "Mistral API 키를 입력하세요",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API 키",
"vercelAiGatewayApiKeyPlaceholder": "Vercel AI Gateway API 키를 입력하세요",
"openaiCompatibleProvider": "OpenAI 호환",
"openAiKeyLabel": "OpenAI API 키",
"openAiKeyPlaceholder": "OpenAI API 키를 입력하세요",
@ -113,6 +116,7 @@
"modelDimensionRequired": "모델 차원이 필요합니다",
"geminiApiKeyRequired": "Gemini API 키가 필요합니다",
"mistralApiKeyRequired": "Mistral API 키가 필요합니다",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway API 키가 필요합니다",
"ollamaBaseUrlRequired": "Ollama 기본 URL이 필요합니다",
"baseUrlRequired": "기본 URL이 필요합니다",
"modelDimensionMinValue": "모델 차원은 0보다 커야 합니다"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "API-sleutel:",
"geminiApiKeyPlaceholder": "Voer uw Gemini API-sleutel in",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API-sleutel",
"vercelAiGatewayApiKeyPlaceholder": "Voer uw Vercel AI Gateway API-sleutel in",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API-sleutel:",
"mistralApiKeyPlaceholder": "Voer uw Mistral API-sleutel in",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Modelafmeting is vereist",
"geminiApiKeyRequired": "Gemini API-sleutel is vereist",
"mistralApiKeyRequired": "Mistral API-sleutel is vereist",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway API-sleutel is vereist",
"ollamaBaseUrlRequired": "Ollama basis-URL is vereist",
"baseUrlRequired": "Basis-URL is vereist",
"modelDimensionMinValue": "Modelafmeting moet groter zijn dan 0"

View file

@ -50,6 +50,9 @@
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Klucz API:",
"mistralApiKeyPlaceholder": "Wprowadź swój klucz API Mistral",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Klucz API",
"vercelAiGatewayApiKeyPlaceholder": "Wprowadź swój klucz API Vercel AI Gateway",
"openaiCompatibleProvider": "Kompatybilny z OpenAI",
"openAiKeyLabel": "Klucz API OpenAI",
"openAiKeyPlaceholder": "Wprowadź swój klucz API OpenAI",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Wymagany jest wymiar modelu",
"geminiApiKeyRequired": "Wymagany jest klucz API Gemini",
"mistralApiKeyRequired": "Klucz API Mistral jest wymagany",
"vercelAiGatewayApiKeyRequired": "Klucz API Vercel AI Gateway jest wymagany",
"ollamaBaseUrlRequired": "Wymagany jest bazowy adres URL Ollama",
"baseUrlRequired": "Wymagany jest bazowy adres URL",
"modelDimensionMinValue": "Wymiar modelu musi być większy niż 0"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "Chave de API:",
"geminiApiKeyPlaceholder": "Digite sua chave de API do Gemini",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Chave de API",
"vercelAiGatewayApiKeyPlaceholder": "Digite sua chave de API do Vercel AI Gateway",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Chave de API:",
"mistralApiKeyPlaceholder": "Digite sua chave de API da Mistral",
@ -113,6 +116,7 @@
"modelDimensionRequired": "A dimensão do modelo é obrigatória",
"geminiApiKeyRequired": "A chave de API do Gemini é obrigatória",
"mistralApiKeyRequired": "A chave de API Mistral é obrigatória",
"vercelAiGatewayApiKeyRequired": "A chave de API do Vercel AI Gateway é obrigatória",
"ollamaBaseUrlRequired": "A URL base do Ollama é obrigatória",
"baseUrlRequired": "A URL base é obrigatória",
"modelDimensionMinValue": "A dimensão do modelo deve ser maior que 0"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "Ключ API:",
"geminiApiKeyPlaceholder": "Введите свой API-ключ Gemini",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Ключ API",
"vercelAiGatewayApiKeyPlaceholder": "Введите свой API-ключ Vercel AI Gateway",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Ключ API:",
"mistralApiKeyPlaceholder": "Введите свой API-ключ Mistral",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Требуется размерность модели",
"geminiApiKeyRequired": "Требуется ключ API Gemini",
"mistralApiKeyRequired": "Требуется API-ключ Mistral",
"vercelAiGatewayApiKeyRequired": "Требуется API-ключ Vercel AI Gateway",
"ollamaBaseUrlRequired": "Требуется базовый URL Ollama",
"baseUrlRequired": "Требуется базовый URL",
"modelDimensionMinValue": "Размерность модели должна быть больше 0"

View file

@ -50,6 +50,9 @@
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API Anahtarı:",
"mistralApiKeyPlaceholder": "Mistral API anahtarınızı girin",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API Anahtarı",
"vercelAiGatewayApiKeyPlaceholder": "Vercel AI Gateway API anahtarınızı girin",
"openaiCompatibleProvider": "OpenAI Uyumlu",
"openAiKeyLabel": "OpenAI API Anahtarı",
"openAiKeyPlaceholder": "OpenAI API anahtarınızı girin",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Model boyutu gereklidir",
"geminiApiKeyRequired": "Gemini API anahtarı gereklidir",
"mistralApiKeyRequired": "Mistral API anahtarı gereklidir",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway API anahtarı gereklidir",
"ollamaBaseUrlRequired": "Ollama temel URL'si gereklidir",
"baseUrlRequired": "Temel URL'si gereklidir",
"modelDimensionMinValue": "Model boyutu 0'dan büyük olmalıdır"

View file

@ -50,6 +50,9 @@
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "Khóa API:",
"mistralApiKeyPlaceholder": "Nhập khóa API Mistral của bạn",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "Khóa API",
"vercelAiGatewayApiKeyPlaceholder": "Nhập khóa API Vercel AI Gateway của bạn",
"openaiCompatibleProvider": "Tương thích OpenAI",
"openAiKeyLabel": "Khóa API OpenAI",
"openAiKeyPlaceholder": "Nhập khóa API OpenAI của bạn",
@ -113,6 +116,7 @@
"modelDimensionRequired": "Yêu cầu kích thước mô hình",
"geminiApiKeyRequired": "Yêu cầu khóa API Gemini",
"mistralApiKeyRequired": "Cần có khóa API của Mistral",
"vercelAiGatewayApiKeyRequired": "Cần có khóa API Vercel AI Gateway",
"ollamaBaseUrlRequired": "Yêu cầu URL cơ sở Ollama",
"baseUrlRequired": "Yêu cầu URL cơ sở",
"modelDimensionMinValue": "Kích thước mô hình phải lớn hơn 0"

View file

@ -52,6 +52,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "API 密钥:",
"geminiApiKeyPlaceholder": "输入您的Gemini API密钥",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API 密钥",
"vercelAiGatewayApiKeyPlaceholder": "输入您的 Vercel AI Gateway API 密钥",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API 密钥:",
"mistralApiKeyPlaceholder": "输入您的 Mistral API 密钥",
@ -113,6 +116,7 @@
"modelDimensionRequired": "需要模型维度",
"geminiApiKeyRequired": "需要 Gemini API 密钥",
"mistralApiKeyRequired": "需要 Mistral API 密钥",
"vercelAiGatewayApiKeyRequired": "需要 Vercel AI Gateway API 密钥",
"ollamaBaseUrlRequired": "需要 Ollama 基础 URL",
"baseUrlRequired": "需要基础 URL",
"modelDimensionMinValue": "模型维度必须大于 0"

View file

@ -47,6 +47,9 @@
"geminiProvider": "Gemini",
"geminiApiKeyLabel": "API 金鑰:",
"geminiApiKeyPlaceholder": "輸入您的 Gemini API 金鑰",
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API 金鑰",
"vercelAiGatewayApiKeyPlaceholder": "輸入您的 Vercel AI Gateway API 金鑰",
"mistralProvider": "Mistral",
"mistralApiKeyLabel": "API 金鑰:",
"mistralApiKeyPlaceholder": "輸入您的 Mistral API 金鑰",
@ -113,6 +116,7 @@
"modelDimensionRequired": "需要模型維度",
"geminiApiKeyRequired": "需要 Gemini API 金鑰",
"mistralApiKeyRequired": "需要 Mistral API 金鑰",
"vercelAiGatewayApiKeyRequired": "需要 Vercel AI Gateway API 金鑰",
"ollamaBaseUrlRequired": "需要 Ollama 基礎 URL",
"baseUrlRequired": "需要基礎 URL",
"modelDimensionMinValue": "模型維度必須大於 0"