diff --git a/packages/types/src/codebase-index.ts b/packages/types/src/codebase-index.ts index be7778f53875..424c17e000c2 100644 --- a/packages/types/src/codebase-index.ts +++ b/packages/types/src/codebase-index.ts @@ -22,7 +22,7 @@ export const codebaseIndexConfigSchema = z.object({ codebaseIndexEnabled: z.boolean().optional(), codebaseIndexQdrantUrl: z.string().optional(), codebaseIndexEmbedderProvider: z - .enum(["openai", "ollama", "openai-compatible", "gemini", "mistral", "vercel-ai-gateway"]) + .enum(["openai", "ollama", "openai-compatible", "gemini", "mistral", "vercel-ai-gateway", "openrouter"]) .optional(), codebaseIndexEmbedderBaseUrl: z.string().optional(), codebaseIndexEmbedderModelId: z.string().optional(), @@ -51,6 +51,7 @@ export const codebaseIndexModelsSchema = z.object({ 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(), + openrouter: z.record(z.string(), z.object({ dimension: z.number() })).optional(), }) export type CodebaseIndexModels = z.infer diff --git a/src/i18n/locales/ca/embeddings.json b/src/i18n/locales/ca/embeddings.json index 782f92cddfdf..90dc187b020d 100644 --- a/src/i18n/locales/ca/embeddings.json +++ b/src/i18n/locales/ca/embeddings.json @@ -52,7 +52,8 @@ "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ó.", "qdrantUrlMissing": "Falta l'URL de Qdrant per crear l'emmagatzematge de vectors", - "codeIndexingNotConfigured": "No es poden crear serveis: La indexació de codi no està configurada correctament" + "codeIndexingNotConfigured": "No es poden crear serveis: La indexació de codi no està configurada correctament", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Indexació fallida: No s'ha indexat cap bloc de codi amb èxit. Això normalment indica un problema de configuració de l'embedder.", diff --git a/src/i18n/locales/de/embeddings.json b/src/i18n/locales/de/embeddings.json index 239d5d3c8a09..a162c5331631 100644 --- a/src/i18n/locales/de/embeddings.json +++ b/src/i18n/locales/de/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "Qdrant-URL fehlt für die Erstellung des Vektorspeichers", - "codeIndexingNotConfigured": "Kann keine Dienste erstellen: Code-Indizierung ist nicht richtig konfiguriert" + "codeIndexingNotConfigured": "Kann keine Dienste erstellen: Code-Indizierung ist nicht richtig konfiguriert", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Indizierung fehlgeschlagen: Keine Code-Blöcke wurden erfolgreich indiziert. Dies deutet normalerweise auf ein Embedder-Konfigurationsproblem hin.", diff --git a/src/i18n/locales/en/embeddings.json b/src/i18n/locales/en/embeddings.json index fc902cadc165..1d1f45513170 100644 --- a/src/i18n/locales/en/embeddings.json +++ b/src/i18n/locales/en/embeddings.json @@ -48,6 +48,7 @@ "geminiConfigMissing": "Gemini configuration missing for embedder creation", "mistralConfigMissing": "Mistral configuration missing for embedder creation", "vercelAiGatewayConfigMissing": "Vercel AI Gateway configuration missing for embedder creation", + "openRouterConfigMissing": "OpenRouter 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.", diff --git a/src/i18n/locales/es/embeddings.json b/src/i18n/locales/es/embeddings.json index ac7522ab0147..3b84617502c3 100644 --- a/src/i18n/locales/es/embeddings.json +++ b/src/i18n/locales/es/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "Falta la URL de Qdrant para crear el almacén de vectores", - "codeIndexingNotConfigured": "No se pueden crear servicios: La indexación de código no está configurada correctamente" + "codeIndexingNotConfigured": "No se pueden crear servicios: La indexación de código no está configurada correctamente", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Indexación fallida: No se indexaron exitosamente bloques de código. Esto usualmente indica un problema de configuración del incrustador.", diff --git a/src/i18n/locales/fr/embeddings.json b/src/i18n/locales/fr/embeddings.json index e4dff2801298..72d4955db8b9 100644 --- a/src/i18n/locales/fr/embeddings.json +++ b/src/i18n/locales/fr/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "URL Qdrant manquante pour la création du stockage de vecteurs", - "codeIndexingNotConfigured": "Impossible de créer les services : L'indexation du code n'est pas correctement configurée" + "codeIndexingNotConfigured": "Impossible de créer les services : L'indexation du code n'est pas correctement configurée", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Échec de l'indexation : Aucun bloc de code n'a été indexé avec succès. Cela indique généralement un problème de configuration de l'embedder.", diff --git a/src/i18n/locales/hi/embeddings.json b/src/i18n/locales/hi/embeddings.json index 108d12637302..c16bbc02380b 100644 --- a/src/i18n/locales/hi/embeddings.json +++ b/src/i18n/locales/hi/embeddings.json @@ -52,7 +52,8 @@ "vectorDimensionNotDeterminedOpenAiCompatible": "प्रदाता '{{provider}}' के साथ मॉडल '{{modelId}}' के लिए वेक्टर आयाम निर्धारित नहीं कर सका। कृपया सुनिश्चित करें कि OpenAI-संगत प्रदाता सेटिंग्स में 'एम्बेडिंग आयाम' सही तरीके से सेट है।", "vectorDimensionNotDetermined": "प्रदाता '{{provider}}' के साथ मॉडल '{{modelId}}' के लिए वेक्टर आयाम निर्धारित नहीं कर सका। मॉडल प्रोफ़ाइल या कॉन्फ़िगरेशन की जांच करें।", "qdrantUrlMissing": "वेक्टर स्टोर बनाने के लिए Qdrant URL गायब है", - "codeIndexingNotConfigured": "सेवाएं नहीं बना सकते: कोड इंडेक्सिंग ठीक से कॉन्फ़िगर नहीं है" + "codeIndexingNotConfigured": "सेवाएं नहीं बना सकते: कोड इंडेक्सिंग ठीक से कॉन्फ़िगर नहीं है", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "इंडेक्सिंग असफल: कोई भी कोड ब्लॉक सफलतापूर्वक इंडेक्स नहीं हुआ। यह आमतौर पर एम्बेडर कॉन्फ़िगरेशन समस्या को दर्शाता है।", diff --git a/src/i18n/locales/id/embeddings.json b/src/i18n/locales/id/embeddings.json index 8c0fdd490fac..6082eb8c4d95 100644 --- a/src/i18n/locales/id/embeddings.json +++ b/src/i18n/locales/id/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "URL Qdrant tidak ada untuk membuat penyimpanan vektor", - "codeIndexingNotConfigured": "Tidak dapat membuat layanan: Pengindeksan kode tidak dikonfigurasi dengan benar" + "codeIndexingNotConfigured": "Tidak dapat membuat layanan: Pengindeksan kode tidak dikonfigurasi dengan benar", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Pengindeksan gagal: Tidak ada blok kode yang berhasil diindeks. Ini biasanya menunjukkan masalah konfigurasi embedder.", diff --git a/src/i18n/locales/it/embeddings.json b/src/i18n/locales/it/embeddings.json index 0ca32f906ea0..64cdf2b0bc40 100644 --- a/src/i18n/locales/it/embeddings.json +++ b/src/i18n/locales/it/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "URL Qdrant mancante per la creazione dello storage vettoriale", - "codeIndexingNotConfigured": "Impossibile creare i servizi: L'indicizzazione del codice non è configurata correttamente" + "codeIndexingNotConfigured": "Impossibile creare i servizi: L'indicizzazione del codice non è configurata correttamente", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Indicizzazione fallita: Nessun blocco di codice è stato indicizzato con successo. Questo di solito indica un problema di configurazione dell'embedder.", diff --git a/src/i18n/locales/ja/embeddings.json b/src/i18n/locales/ja/embeddings.json index a1a37ebffa31..79b41689f583 100644 --- a/src/i18n/locales/ja/embeddings.json +++ b/src/i18n/locales/ja/embeddings.json @@ -52,7 +52,8 @@ "vectorDimensionNotDeterminedOpenAiCompatible": "プロバイダー '{{provider}}' のモデル '{{modelId}}' の埋め込み次元を決定できませんでした。OpenAI互換プロバイダー設定で「埋め込み次元」が正しく設定されていることを確認してください。", "vectorDimensionNotDetermined": "プロバイダー '{{provider}}' のモデル '{{modelId}}' の埋め込み次元を決定できませんでした。モデルプロファイルまたは設定を確認してください。", "qdrantUrlMissing": "ベクターストア作成のためのQdrant URLがありません", - "codeIndexingNotConfigured": "サービスを作成できません: コードインデックスが正しく設定されていません" + "codeIndexingNotConfigured": "サービスを作成できません: コードインデックスが正しく設定されていません", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "インデックス作成に失敗しました:コードブロックが正常にインデックス化されませんでした。これは通常、エンベッダーの設定問題を示しています。", diff --git a/src/i18n/locales/ko/embeddings.json b/src/i18n/locales/ko/embeddings.json index 6c81c9d7d75c..2552dc9976c1 100644 --- a/src/i18n/locales/ko/embeddings.json +++ b/src/i18n/locales/ko/embeddings.json @@ -52,7 +52,8 @@ "vectorDimensionNotDeterminedOpenAiCompatible": "프로바이더 '{{provider}}'의 모델 '{{modelId}}'에 대한 벡터 차원을 결정할 수 없습니다. OpenAI 호환 프로바이더 설정에서 '임베딩 차원'이 올바르게 설정되어 있는지 확인하세요.", "vectorDimensionNotDetermined": "프로바이더 '{{provider}}'의 모델 '{{modelId}}'에 대한 벡터 차원을 결정할 수 없습니다. 모델 프로필 또는 구성을 확인하세요.", "qdrantUrlMissing": "벡터 저장소 생성을 위한 Qdrant URL이 누락되었습니다", - "codeIndexingNotConfigured": "서비스를 생성할 수 없습니다: 코드 인덱싱이 올바르게 구성되지 않았습니다" + "codeIndexingNotConfigured": "서비스를 생성할 수 없습니다: 코드 인덱싱이 올바르게 구성되지 않았습니다", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "인덱싱 실패: 코드 블록이 성공적으로 인덱싱되지 않았습니다. 이는 일반적으로 임베더 구성 문제를 나타냅니다.", diff --git a/src/i18n/locales/nl/embeddings.json b/src/i18n/locales/nl/embeddings.json index 7ae59ae02a60..a41adff2a45c 100644 --- a/src/i18n/locales/nl/embeddings.json +++ b/src/i18n/locales/nl/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "Qdrant URL ontbreekt voor het maken van vectoropslag", - "codeIndexingNotConfigured": "Kan geen services maken: Code-indexering is niet correct geconfigureerd" + "codeIndexingNotConfigured": "Kan geen services maken: Code-indexering is niet correct geconfigureerd", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Indexering mislukt: Geen codeblokken werden succesvol geïndexeerd. Dit duidt meestal op een embedder configuratieprobleem.", diff --git a/src/i18n/locales/pl/embeddings.json b/src/i18n/locales/pl/embeddings.json index 8f75d00af88f..955247fca967 100644 --- a/src/i18n/locales/pl/embeddings.json +++ b/src/i18n/locales/pl/embeddings.json @@ -52,7 +52,8 @@ "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ę.", "qdrantUrlMissing": "Brak adresu URL Qdrant do utworzenia magazynu wektorów", - "codeIndexingNotConfigured": "Nie można utworzyć usług: Indeksowanie kodu nie jest poprawnie skonfigurowane" + "codeIndexingNotConfigured": "Nie można utworzyć usług: Indeksowanie kodu nie jest poprawnie skonfigurowane", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Indeksowanie nie powiodło się: Żadne bloki kodu nie zostały pomyślnie zaindeksowane. To zwykle wskazuje na problem z konfiguracją embeddera.", diff --git a/src/i18n/locales/pt-BR/embeddings.json b/src/i18n/locales/pt-BR/embeddings.json index ee135ed8b526..7e614f72520c 100644 --- a/src/i18n/locales/pt-BR/embeddings.json +++ b/src/i18n/locales/pt-BR/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "URL do Qdrant ausente para criação do armazenamento de vetores", - "codeIndexingNotConfigured": "Não é possível criar serviços: A indexação de código não está configurada corretamente" + "codeIndexingNotConfigured": "Não é possível criar serviços: A indexação de código não está configurada corretamente", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Indexação falhou: Nenhum bloco de código foi indexado com sucesso. Isso geralmente indica um problema de configuração do embedder.", diff --git a/src/i18n/locales/ru/embeddings.json b/src/i18n/locales/ru/embeddings.json index 97301b32097e..b7e58aa36515 100644 --- a/src/i18n/locales/ru/embeddings.json +++ b/src/i18n/locales/ru/embeddings.json @@ -52,7 +52,8 @@ "vectorDimensionNotDeterminedOpenAiCompatible": "Не удалось определить размерность вектора для модели '{{modelId}}' с провайдером '{{provider}}'. Убедитесь, что 'Размерность эмбеддинга' правильно установлена в настройках провайдера, совместимого с OpenAI.", "vectorDimensionNotDetermined": "Не удалось определить размерность вектора для модели '{{modelId}}' с провайдером '{{provider}}'. Проверьте профили модели или конфигурацию.", "qdrantUrlMissing": "Отсутствует URL Qdrant для создания векторного хранилища", - "codeIndexingNotConfigured": "Невозможно создать сервисы: Индексация кода не настроена должным образом" + "codeIndexingNotConfigured": "Невозможно создать сервисы: Индексация кода не настроена должным образом", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Индексация не удалась: Ни один блок кода не был успешно проиндексирован. Это обычно указывает на проблему конфигурации эмбеддера.", diff --git a/src/i18n/locales/tr/embeddings.json b/src/i18n/locales/tr/embeddings.json index 279fa97516a4..5f091dca6b52 100644 --- a/src/i18n/locales/tr/embeddings.json +++ b/src/i18n/locales/tr/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "Vektör deposu oluşturmak için Qdrant URL'si eksik", - "codeIndexingNotConfigured": "Hizmetler oluşturulamıyor: Kod indeksleme düzgün yapılandırılmamış" + "codeIndexingNotConfigured": "Hizmetler oluşturulamıyor: Kod indeksleme düzgün yapılandırılmamış", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "İndeksleme başarısız: Hiçbir kod bloğu başarıyla indekslenemedi. Bu genellikle bir embedder yapılandırma sorunu olduğunu gösterir.", diff --git a/src/i18n/locales/vi/embeddings.json b/src/i18n/locales/vi/embeddings.json index 3e941aafb666..5de5a4eec395 100644 --- a/src/i18n/locales/vi/embeddings.json +++ b/src/i18n/locales/vi/embeddings.json @@ -52,7 +52,8 @@ "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.", "qdrantUrlMissing": "Thiếu URL Qdrant để tạo kho lưu trữ vector", - "codeIndexingNotConfigured": "Không thể tạo dịch vụ: Lập chỉ mục mã không được cấu hình đúng cách" + "codeIndexingNotConfigured": "Không thể tạo dịch vụ: Lập chỉ mục mã không được cấu hình đúng cách", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "Lập chỉ mục thất bại: Không có khối mã nào được lập chỉ mục thành công. Điều này thường cho thấy vấn đề cấu hình embedder.", diff --git a/src/i18n/locales/zh-CN/embeddings.json b/src/i18n/locales/zh-CN/embeddings.json index d16f7df32b20..2b43c7d01b29 100644 --- a/src/i18n/locales/zh-CN/embeddings.json +++ b/src/i18n/locales/zh-CN/embeddings.json @@ -52,7 +52,8 @@ "vectorDimensionNotDeterminedOpenAiCompatible": "无法确定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量维度。请确保在 OpenAI 兼容提供商设置中正确设置了「嵌入维度」。", "vectorDimensionNotDetermined": "无法确定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量维度。请检查模型配置文件或配置。", "qdrantUrlMissing": "创建向量存储缺少 Qdrant URL", - "codeIndexingNotConfigured": "无法创建服务:代码索引未正确配置" + "codeIndexingNotConfigured": "无法创建服务:代码索引未正确配置", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "索引失败:没有代码块被成功索引。这通常表示 Embedder 配置问题。", diff --git a/src/i18n/locales/zh-TW/embeddings.json b/src/i18n/locales/zh-TW/embeddings.json index 044de1dac229..d0ab06734db4 100644 --- a/src/i18n/locales/zh-TW/embeddings.json +++ b/src/i18n/locales/zh-TW/embeddings.json @@ -52,7 +52,8 @@ "vectorDimensionNotDeterminedOpenAiCompatible": "無法確定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量維度。請確保在 OpenAI 相容提供商設定中正確設定了「嵌入維度」。", "vectorDimensionNotDetermined": "無法確定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量維度。請檢查模型設定檔或設定。", "qdrantUrlMissing": "建立向量儲存缺少 Qdrant URL", - "codeIndexingNotConfigured": "無法建立服務:程式碼索引未正確設定" + "codeIndexingNotConfigured": "無法建立服務:程式碼索引未正確設定", + "openRouterConfigMissing": "OpenRouter configuration missing for embedder creation" }, "orchestrator": { "indexingFailedNoBlocks": "索引失敗:沒有程式碼區塊被成功索引。這通常表示 Embedder 設定問題。", diff --git a/src/services/code-index/config-manager.ts b/src/services/code-index/config-manager.ts index 2c0e8bb5c9e4..6505a7436b3b 100644 --- a/src/services/code-index/config-manager.ts +++ b/src/services/code-index/config-manager.ts @@ -20,6 +20,7 @@ export class CodeIndexConfigManager { private geminiOptions?: { apiKey: string } private mistralOptions?: { apiKey: string } private vercelAiGatewayOptions?: { apiKey: string } + private openRouterOptions?: { apiKey: string; baseUrl?: string } private qdrantUrl?: string = "http://localhost:6333" private qdrantApiKey?: string private searchMinScore?: number @@ -71,6 +72,9 @@ export class CodeIndexConfigManager { const geminiApiKey = this.contextProxy?.getSecret("codebaseIndexGeminiApiKey") ?? "" const mistralApiKey = this.contextProxy?.getSecret("codebaseIndexMistralApiKey") ?? "" const vercelAiGatewayApiKey = this.contextProxy?.getSecret("codebaseIndexVercelAiGatewayApiKey") ?? "" + // Use existing openRouterApiKey from chat model settings for embeddings + const openRouterApiKey = this.contextProxy?.getSecret("openRouterApiKey") ?? "" + const openRouterBaseUrl = codebaseIndexConfig.codebaseIndexEmbedderBaseUrl ?? "" // Update instance variables with configuration this.codebaseIndexEnabled = codebaseIndexEnabled ?? true @@ -108,6 +112,8 @@ export class CodeIndexConfigManager { this.embedderProvider = "mistral" } else if (codebaseIndexEmbedderProvider === "vercel-ai-gateway") { this.embedderProvider = "vercel-ai-gateway" + } else if (codebaseIndexEmbedderProvider === "openrouter") { + this.embedderProvider = "openrouter" } else { this.embedderProvider = "openai" } @@ -129,6 +135,9 @@ export class CodeIndexConfigManager { this.geminiOptions = geminiApiKey ? { apiKey: geminiApiKey } : undefined this.mistralOptions = mistralApiKey ? { apiKey: mistralApiKey } : undefined this.vercelAiGatewayOptions = vercelAiGatewayApiKey ? { apiKey: vercelAiGatewayApiKey } : undefined + this.openRouterOptions = openRouterApiKey + ? { apiKey: openRouterApiKey, baseUrl: openRouterBaseUrl || undefined } + : undefined } /** @@ -147,6 +156,7 @@ export class CodeIndexConfigManager { geminiOptions?: { apiKey: string } mistralOptions?: { apiKey: string } vercelAiGatewayOptions?: { apiKey: string } + openRouterOptions?: { apiKey: string; baseUrl?: string } qdrantUrl?: string qdrantApiKey?: string searchMinScore?: number @@ -167,6 +177,8 @@ export class CodeIndexConfigManager { geminiApiKey: this.geminiOptions?.apiKey ?? "", mistralApiKey: this.mistralOptions?.apiKey ?? "", vercelAiGatewayApiKey: this.vercelAiGatewayOptions?.apiKey ?? "", + openRouterApiKey: this.openRouterOptions?.apiKey ?? "", + openRouterBaseUrl: this.openRouterOptions?.baseUrl ?? "", qdrantUrl: this.qdrantUrl ?? "", qdrantApiKey: this.qdrantApiKey ?? "", } @@ -192,6 +204,7 @@ export class CodeIndexConfigManager { geminiOptions: this.geminiOptions, mistralOptions: this.mistralOptions, vercelAiGatewayOptions: this.vercelAiGatewayOptions, + openRouterOptions: this.openRouterOptions, qdrantUrl: this.qdrantUrl, qdrantApiKey: this.qdrantApiKey, searchMinScore: this.currentSearchMinScore, @@ -234,6 +247,11 @@ export class CodeIndexConfigManager { const qdrantUrl = this.qdrantUrl const isConfigured = !!(apiKey && qdrantUrl) return isConfigured + } else if (this.embedderProvider === "openrouter") { + const apiKey = this.openRouterOptions?.apiKey + const qdrantUrl = this.qdrantUrl + const isConfigured = !!(apiKey && qdrantUrl) + return isConfigured } return false // Should not happen if embedderProvider is always set correctly } @@ -269,6 +287,8 @@ export class CodeIndexConfigManager { const prevGeminiApiKey = prev?.geminiApiKey ?? "" const prevMistralApiKey = prev?.mistralApiKey ?? "" const prevVercelAiGatewayApiKey = prev?.vercelAiGatewayApiKey ?? "" + const prevOpenRouterApiKey = prev?.openRouterApiKey ?? "" + const prevOpenRouterBaseUrl = prev?.openRouterBaseUrl ?? "" const prevQdrantUrl = prev?.qdrantUrl ?? "" const prevQdrantApiKey = prev?.qdrantApiKey ?? "" @@ -307,6 +327,8 @@ export class CodeIndexConfigManager { const currentGeminiApiKey = this.geminiOptions?.apiKey ?? "" const currentMistralApiKey = this.mistralOptions?.apiKey ?? "" const currentVercelAiGatewayApiKey = this.vercelAiGatewayOptions?.apiKey ?? "" + const currentOpenRouterApiKey = this.openRouterOptions?.apiKey ?? "" + const currentOpenRouterBaseUrl = this.openRouterOptions?.baseUrl ?? "" const currentQdrantUrl = this.qdrantUrl ?? "" const currentQdrantApiKey = this.qdrantApiKey ?? "" @@ -337,6 +359,10 @@ export class CodeIndexConfigManager { return true } + if (prevOpenRouterApiKey !== currentOpenRouterApiKey || prevOpenRouterBaseUrl !== currentOpenRouterBaseUrl) { + return true + } + // Check for model dimension changes (generic for all providers) if (prevModelDimension !== currentModelDimension) { return true @@ -395,6 +421,7 @@ export class CodeIndexConfigManager { geminiOptions: this.geminiOptions, mistralOptions: this.mistralOptions, vercelAiGatewayOptions: this.vercelAiGatewayOptions, + openRouterOptions: this.openRouterOptions, qdrantUrl: this.qdrantUrl, qdrantApiKey: this.qdrantApiKey, searchMinScore: this.currentSearchMinScore, diff --git a/src/services/code-index/embedders/__tests__/openrouter.spec.ts b/src/services/code-index/embedders/__tests__/openrouter.spec.ts new file mode 100644 index 000000000000..c21b437704ea --- /dev/null +++ b/src/services/code-index/embedders/__tests__/openrouter.spec.ts @@ -0,0 +1,96 @@ +// npx vitest run src/services/code-index/embedders/__tests__/openrouter.spec.ts + +import { describe, it, expect, vi, beforeEach } from "vitest" +import { OpenRouterEmbedder } from "../openrouter" +import { OpenAICompatibleEmbedder } from "../openai-compatible" +import { t } from "../../../../i18n" + +vi.mock("../../../../i18n", () => ({ + t: (key: string, params?: any) => { + const translations: Record = { + "embeddings:validation.apiKeyRequired": "API key is required", + } + return translations[key] || key + }, +})) + +// Mock the parent class +vi.mock("../openai-compatible") + +describe("OpenRouterEmbedder", () => { + beforeEach(() => { + vi.clearAllMocks() + // Mock the OpenAICompatibleEmbedder constructor + vi.mocked(OpenAICompatibleEmbedder).mockImplementation(function ( + this: any, + baseUrl: string, + apiKey: string, + modelId: string, + maxTokens: number, + ) { + // Store constructor arguments for verification + this.baseUrl = baseUrl + this.apiKey = apiKey + this.modelId = modelId + this.maxTokens = maxTokens + + // Mock methods + this.createEmbeddings = vi.fn() + this.validateConfiguration = vi.fn() + + // Return this for chaining + return this + } as any) + }) + + describe("constructor", () => { + it("should create an instance with valid API key", () => { + const embedder = new OpenRouterEmbedder("test-api-key") + expect(embedder).toBeDefined() + expect(OpenAICompatibleEmbedder).toHaveBeenCalledWith( + "https://openrouter.ai/api/v1", + "test-api-key", + "openai/text-embedding-3-small", + 8191, + ) + }) + + it("should use custom model ID when provided", () => { + const embedder = new OpenRouterEmbedder("test-api-key", "openai/text-embedding-3-large") + expect(embedder).toBeDefined() + expect(OpenAICompatibleEmbedder).toHaveBeenCalledWith( + "https://openrouter.ai/api/v1", + "test-api-key", + "openai/text-embedding-3-large", + 8191, + ) + }) + + it("should use custom base URL when provided", () => { + const embedder = new OpenRouterEmbedder("test-api-key", undefined, "https://custom.openrouter.ai/api/v1") + expect(embedder).toBeDefined() + expect(OpenAICompatibleEmbedder).toHaveBeenCalledWith( + "https://custom.openrouter.ai/api/v1", + "test-api-key", + "openai/text-embedding-3-small", + 8191, + ) + }) + + it("should throw error when API key is not provided", () => { + expect(() => new OpenRouterEmbedder(undefined as any)).toThrow("API key is required") + }) + + it("should throw error when API key is empty string", () => { + expect(() => new OpenRouterEmbedder("")).toThrow("API key is required") + }) + }) + + describe("embedderInfo", () => { + it("should return openrouter as the embedder name", () => { + const embedder = new OpenRouterEmbedder("test-api-key") + // The embedderInfo getter in OpenRouterEmbedder overrides the parent class + expect(embedder.embedderInfo).toEqual({ name: "openrouter" }) + }) + }) +}) diff --git a/src/services/code-index/embedders/openrouter.ts b/src/services/code-index/embedders/openrouter.ts new file mode 100644 index 000000000000..5976ea2dd328 --- /dev/null +++ b/src/services/code-index/embedders/openrouter.ts @@ -0,0 +1,53 @@ +import { OpenAICompatibleEmbedder } from "./openai-compatible" +import { IEmbedder, EmbedderInfo } from "../interfaces/embedder" +import { getDefaultModelId } from "../../../shared/embeddingModels" +import { MAX_ITEM_TOKENS } from "../constants" +import { t } from "../../../i18n" + +/** + * OpenRouter embedder implementation that wraps the OpenAI Compatible embedder + * with configuration for OpenRouter'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-english-v3.0 (dimension: 1024) + * - cohere/embed-multilingual-v3.0 (dimension: 1024) + * - voyage/voyage-3 (dimension: 1024) + * - voyage/voyage-3-lite (dimension: 512) + */ +export class OpenRouterEmbedder extends OpenAICompatibleEmbedder implements IEmbedder { + private static readonly OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1" + private static readonly DEFAULT_MODEL = "openai/text-embedding-3-small" + private readonly modelId: string + + /** + * Creates a new OpenRouter embedder + * @param apiKey The OpenRouter API key for authentication + * @param modelId The model ID to use (defaults to openai/text-embedding-3-small) + * @param baseUrl Optional custom base URL for OpenRouter API (defaults to https://openrouter.ai/api/v1) + */ + constructor(apiKey?: string, modelId?: string, baseUrl?: string) { + if (!apiKey) { + throw new Error(t("embeddings:validation.apiKeyRequired")) + } + + // Use the provided base URL or default to OpenRouter's API URL + const openRouterBaseUrl = baseUrl || OpenRouterEmbedder.OPENROUTER_BASE_URL + + // Initialize the parent OpenAI Compatible embedder with OpenRouter configuration + super(openRouterBaseUrl, apiKey, modelId || OpenRouterEmbedder.DEFAULT_MODEL, MAX_ITEM_TOKENS) + + this.modelId = modelId || getDefaultModelId("openrouter") + } + + /** + * Returns information about this embedder + */ + override get embedderInfo(): EmbedderInfo { + return { + name: "openrouter", + } + } +} diff --git a/src/services/code-index/interfaces/config.ts b/src/services/code-index/interfaces/config.ts index f168e268691a..2ddbd35d9eff 100644 --- a/src/services/code-index/interfaces/config.ts +++ b/src/services/code-index/interfaces/config.ts @@ -15,6 +15,7 @@ export interface CodeIndexConfig { geminiOptions?: { apiKey: string } mistralOptions?: { apiKey: string } vercelAiGatewayOptions?: { apiKey: string } + openRouterOptions?: { apiKey: string; baseUrl?: string } qdrantUrl?: string qdrantApiKey?: string searchMinScore?: number @@ -37,6 +38,8 @@ export type PreviousConfigSnapshot = { geminiApiKey?: string mistralApiKey?: string vercelAiGatewayApiKey?: string + openRouterApiKey?: string + openRouterBaseUrl?: string qdrantUrl?: string qdrantApiKey?: string } diff --git a/src/services/code-index/interfaces/embedder.ts b/src/services/code-index/interfaces/embedder.ts index 1fcda3aca32d..7a3aa91ad9d8 100644 --- a/src/services/code-index/interfaces/embedder.ts +++ b/src/services/code-index/interfaces/embedder.ts @@ -28,7 +28,14 @@ export interface EmbeddingResponse { } } -export type AvailableEmbedders = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral" | "vercel-ai-gateway" +export type AvailableEmbedders = + | "openai" + | "ollama" + | "openai-compatible" + | "gemini" + | "mistral" + | "vercel-ai-gateway" + | "openrouter" export interface EmbedderInfo { name: AvailableEmbedders diff --git a/src/services/code-index/interfaces/manager.ts b/src/services/code-index/interfaces/manager.ts index 527900f6d1c7..9a6e4031ab11 100644 --- a/src/services/code-index/interfaces/manager.ts +++ b/src/services/code-index/interfaces/manager.ts @@ -70,7 +70,14 @@ export interface ICodeIndexManager { } export type IndexingState = "Standby" | "Indexing" | "Indexed" | "Error" -export type EmbedderProvider = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral" | "vercel-ai-gateway" +export type EmbedderProvider = + | "openai" + | "ollama" + | "openai-compatible" + | "gemini" + | "mistral" + | "vercel-ai-gateway" + | "openrouter" export interface IndexProgressUpdate { systemStatus: IndexingState diff --git a/src/services/code-index/service-factory.ts b/src/services/code-index/service-factory.ts index 6d69e1f0b6c6..bcffd9732ae2 100644 --- a/src/services/code-index/service-factory.ts +++ b/src/services/code-index/service-factory.ts @@ -5,6 +5,7 @@ import { OpenAICompatibleEmbedder } from "./embedders/openai-compatible" import { GeminiEmbedder } from "./embedders/gemini" import { MistralEmbedder } from "./embedders/mistral" import { VercelAiGatewayEmbedder } from "./embedders/vercel-ai-gateway" +import { OpenRouterEmbedder } from "./embedders/openrouter" import { EmbedderProvider, getDefaultModelId, getModelDimension } from "../../shared/embeddingModels" import { QdrantVectorStore } from "./vector-store/qdrant-client" import { codeParser, DirectoryScanner, FileWatcher } from "./processors" @@ -79,6 +80,15 @@ export class CodeIndexServiceFactory { throw new Error(t("embeddings:serviceFactory.vercelAiGatewayConfigMissing")) } return new VercelAiGatewayEmbedder(config.vercelAiGatewayOptions.apiKey, config.modelId) + } else if (provider === "openrouter") { + if (!config.openRouterOptions?.apiKey) { + throw new Error(t("embeddings:serviceFactory.openRouterConfigMissing")) + } + return new OpenRouterEmbedder( + config.openRouterOptions.apiKey, + config.modelId, + config.openRouterOptions.baseUrl, + ) } throw new Error( diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 9c475186288f..7f3280bb2395 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -292,6 +292,7 @@ export interface WebviewMessage { | "gemini" | "mistral" | "vercel-ai-gateway" + | "openrouter" codebaseIndexEmbedderBaseUrl?: string codebaseIndexEmbedderModelId: string codebaseIndexEmbedderModelDimension?: number // Generic dimension for all providers diff --git a/src/shared/embeddingModels.ts b/src/shared/embeddingModels.ts index 80c51a6b4558..a8655df7263b 100644 --- a/src/shared/embeddingModels.ts +++ b/src/shared/embeddingModels.ts @@ -2,7 +2,14 @@ * Defines profiles for different embedding models, including their dimensions. */ -export type EmbedderProvider = "openai" | "ollama" | "openai-compatible" | "gemini" | "mistral" | "vercel-ai-gateway" // Add other providers as needed +export type EmbedderProvider = + | "openai" + | "ollama" + | "openai-compatible" + | "gemini" + | "mistral" + | "vercel-ai-gateway" + | "openrouter" // Add other providers as needed export interface EmbeddingModelProfile { dimension: number @@ -70,6 +77,19 @@ export const EMBEDDING_MODEL_PROFILES: EmbeddingModelProfiles = { "mistral/codestral-embed": { dimension: 1536, scoreThreshold: 0.4 }, "mistral/mistral-embed": { dimension: 1024, scoreThreshold: 0.4 }, }, + openrouter: { + // OpenAI models available via OpenRouter + "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-english-v3.0": { dimension: 1024, scoreThreshold: 0.4 }, + "cohere/embed-multilingual-v3.0": { dimension: 1024, scoreThreshold: 0.4 }, + // Voyage models + "voyage/voyage-embeddings-v3": { dimension: 1024, scoreThreshold: 0.4 }, + "voyage/voyage-3": { dimension: 1024, scoreThreshold: 0.4 }, + "voyage/voyage-3-lite": { dimension: 512, scoreThreshold: 0.4 }, + }, } /** @@ -163,6 +183,9 @@ export function getDefaultModelId(provider: EmbedderProvider): string { case "vercel-ai-gateway": return "openai/text-embedding-3-large" + case "openrouter": + return "openai/text-embedding-3-small" + default: // Fallback for unknown providers console.warn(`Unknown provider for default model ID: ${provider}. Falling back to OpenAI default.`)