2026-05-04 00:29:02 -04:00
|
|
|
// Embeddings provider adapter registry
|
|
|
|
|
import createOpenAIEmbeddingAdapter from "./openai.js";
|
|
|
|
|
import gemini from "./gemini.js";
|
|
|
|
|
import openaiCompatNode from "./openaiCompatNode.js";
|
feat(providers): self-hosted OpenAI-compatible STT, TTS and embedding providers
Add Self-hosted STT/TTS/Embedding providers that read baseUrl per connection
instead of a fixed registry endpoint, so 9Router can point at whisper.cpp,
faster-whisper, Kokoro-FastAPI, llama-server, vLLM, Infinity, and similar
OpenAI-compatible local servers.
Self-hosted Embedding refuses to run without a baseUrl rather than falling
back to api.openai.com like openaiCompatNode does, since that fallback would
silently send input text and the API key to OpenAI under a provider named
"Self-hosted". Also fixes embeddingsCore to catch adapter build errors as a
400 instead of letting them escape uncaught, and bounds the upstream fetch
with FETCH_CONNECT_TIMEOUT_MS to avoid hanging forever on a dead endpoint.
Self-hosted TTS treats a bare model value as the model rather than the voice,
since the generic OpenAI TTS convention (bare = voice) is backwards for a
provider where the model is the variable part.
2026-08-05 02:33:28 -04:00
|
|
|
import selfhostedEmbedding from "./selfhostedEmbedding.js";
|
2026-05-04 00:29:02 -04:00
|
|
|
|
|
|
|
|
const OPENAI_COMPAT_PROVIDERS = [
|
|
|
|
|
"openai", "openrouter", "mistral", "voyage-ai", "fireworks",
|
|
|
|
|
"together", "nebius", "github", "nvidia", "jina-ai",
|
2026-06-12 23:54:51 -04:00
|
|
|
"vercel-ai-gateway",
|
2026-05-04 00:29:02 -04:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const ADAPTERS = {
|
|
|
|
|
...Object.fromEntries(OPENAI_COMPAT_PROVIDERS.map((id) => [id, createOpenAIEmbeddingAdapter(id)])),
|
|
|
|
|
gemini,
|
|
|
|
|
google_ai_studio: gemini,
|
feat(providers): self-hosted OpenAI-compatible STT, TTS and embedding providers
Add Self-hosted STT/TTS/Embedding providers that read baseUrl per connection
instead of a fixed registry endpoint, so 9Router can point at whisper.cpp,
faster-whisper, Kokoro-FastAPI, llama-server, vLLM, Infinity, and similar
OpenAI-compatible local servers.
Self-hosted Embedding refuses to run without a baseUrl rather than falling
back to api.openai.com like openaiCompatNode does, since that fallback would
silently send input text and the API key to OpenAI under a provider named
"Self-hosted". Also fixes embeddingsCore to catch adapter build errors as a
400 instead of letting them escape uncaught, and bounds the upstream fetch
with FETCH_CONNECT_TIMEOUT_MS to avoid hanging forever on a dead endpoint.
Self-hosted TTS treats a bare model value as the model rather than the voice,
since the generic OpenAI TTS convention (bare = voice) is backwards for a
provider where the model is the variable part.
2026-08-05 02:33:28 -04:00
|
|
|
// Self-hosted reads creds.providerSpecificData.baseUrl (one provider, many
|
|
|
|
|
// servers) — but via its OWN adapter, not openaiCompatNode: that one falls back
|
|
|
|
|
// to api.openai.com when no baseUrl is set, which under a provider called
|
|
|
|
|
// "Self-hosted Embedding" means silently shipping the input and API key to
|
|
|
|
|
// OpenAI. selfhostedEmbedding refuses instead.
|
|
|
|
|
"selfhosted-embedding": selfhostedEmbedding,
|
2026-05-04 00:29:02 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function getEmbeddingAdapter(provider) {
|
|
|
|
|
if (ADAPTERS[provider]) return ADAPTERS[provider];
|
|
|
|
|
if (provider?.startsWith?.("openai-compatible-") || provider?.startsWith?.("custom-embedding-")) {
|
|
|
|
|
return openaiCompatNode;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|