diff --git a/common/adapters.ts b/common/adapters.ts index f337b1ef9..eb8bae192 100644 --- a/common/adapters.ts +++ b/common/adapters.ts @@ -150,6 +150,7 @@ export const THIRDPARTY_HANDLERS: { [svc in ThirdPartyFormat]: AIAdapter } = { gemini: 'kobold', arli: 'kobold', 'lm-studio': 'openai', + orcarouter: 'openai', } export const BASIC_PROMPT_ONLY: { [svc in ThirdPartyFormat]?: boolean } = { @@ -176,6 +177,7 @@ export const THIRDPARTY_FORMATS = [ 'arli', 'gemini', 'lm-studio', + 'orcarouter', ] as const export const AI_ADAPTERS = [ @@ -382,6 +384,7 @@ export const FORMAT_LABEL: { [key in ThirdPartyFormat]: string } = { tabby: 'TabbyAPI', vllm: 'vLLM', 'lm-studio': 'LM Studio', + orcarouter: 'OrcaRouter', } export const INSTRUCT_SERVICES: { [key in AIAdapter]?: boolean } = { diff --git a/common/requests/util.ts b/common/requests/util.ts index 1f3c89027..f8969bdbb 100644 --- a/common/requests/util.ts +++ b/common/requests/util.ts @@ -204,6 +204,13 @@ export function getOaiCompatibleUrl( preset: Partial, isThirdParty?: boolean ) { + // OrcaRouter is an OpenAI-compatible gateway with a fixed endpoint. When its + // format is selected without a custom URL, default to the OrcaRouter API so + // users only need to provide their API key. + if (isThirdParty && preset.thirdPartyFormat === 'orcarouter' && !preset.thirdPartyUrl) { + return { url: 'https://api.orcarouter.ai/v1', changed: true } + } + if (isThirdParty && preset.thirdPartyUrl) { if (!preset.providerId && preset.thirdPartyUrlNoSuffix) { return { url: preset.thirdPartyUrl, changed: true } diff --git a/srv/adapter/openai.ts b/srv/adapter/openai.ts index 9e13115ff..05a734df5 100644 --- a/srv/adapter/openai.ts +++ b/srv/adapter/openai.ts @@ -147,7 +147,8 @@ export const handleOAI: ModelAdapter = async function* (opts) { const isChatFormat = gen.thirdPartyFormat === 'openai-chat' || gen.thirdPartyFormat == 'openai-chatv2' || - gen.thirdPartyFormat === 'lm-studio' + gen.thirdPartyFormat === 'lm-studio' || + gen.thirdPartyFormat === 'orcarouter' const useChat = (isThirdParty && isChatFormat) || gen.service === 'openai' if (useChat) { diff --git a/web/pages/Settings/Provider/index.tsx b/web/pages/Settings/Provider/index.tsx index 8fde0f14f..31b50b981 100644 --- a/web/pages/Settings/Provider/index.tsx +++ b/web/pages/Settings/Provider/index.tsx @@ -296,6 +296,7 @@ const EditConnectionDetails: Field<{ show: boolean; close: () => void }> = (prop 'featherless', 'arli', 'gemini', + 'orcarouter', ] const options = formats.map((id) => ({ label: FORMAT_LABEL[id], value: id as string }))