From 00b98ee0f832f179d2a64952f46c69c1bc5e751e Mon Sep 17 00:00:00 2001 From: DennyHo0917 Date: Sat, 12 Sep 2026 21:47:50 +0800 Subject: [PATCH] feat(llm): add API Route OpenAI-compatible provider --- core/llm/autodetect.ts | 3 + core/llm/llms/ApiRoute.ts | 14 +++ core/llm/llms/index.ts | 2 + .../model-providers/more/apiroute.mdx | 93 ++++++++++++++++++ docs/docs.json | 1 + extensions/vscode/config_schema.json | 12 ++- gui/public/logos/apiroute.png | Bin 0 -> 27008 bytes .../pages/AddNewModel/configs/providers.ts | 21 ++++ packages/openai-adapters/src/index.ts | 2 + packages/openai-adapters/src/types.ts | 1 + 10 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 core/llm/llms/ApiRoute.ts create mode 100644 docs/customize/model-providers/more/apiroute.mdx create mode 100644 gui/public/logos/apiroute.png diff --git a/core/llm/autodetect.ts b/core/llm/autodetect.ts index c8511554b8b..1b6b49485f9 100644 --- a/core/llm/autodetect.ts +++ b/core/llm/autodetect.ts @@ -74,6 +74,7 @@ const PROVIDER_HANDLES_TEMPLATING: string[] = [ "nous", "zAI", "tensorix", + "api-route", // TODO add these, change to inverted logic so only the ones that need templating are hardcoded // Asksage.ts // Azure.ts @@ -133,6 +134,7 @@ const PROVIDER_SUPPORTS_IMAGES: string[] = [ "watsonx", "zAI", "tensorix", + "api-route", ]; const MODEL_SUPPORTS_IMAGES: RegExp[] = [ @@ -253,6 +255,7 @@ const PARALLEL_PROVIDERS: string[] = [ "scaleway", "minimax", "tensorix", + "api-route", ]; function llmCanGenerateInParallel(provider: string, model: string): boolean { diff --git a/core/llm/llms/ApiRoute.ts b/core/llm/llms/ApiRoute.ts new file mode 100644 index 00000000000..484bb458526 --- /dev/null +++ b/core/llm/llms/ApiRoute.ts @@ -0,0 +1,14 @@ +import OpenAI from "./OpenAI.js"; + +import type { LLMOptions } from "../../index.js"; + +class ApiRoute extends OpenAI { + static providerName = "api-route"; + static defaultOptions: Partial = { + apiBase: "https://global.api-route.com/v1/", + model: "claude-3-7-sonnet-20250219", + useLegacyCompletionsEndpoint: false, + }; +} + +export default ApiRoute; diff --git a/core/llm/llms/index.ts b/core/llm/llms/index.ts index 4978f0617f2..45c6906a3d1 100644 --- a/core/llm/llms/index.ts +++ b/core/llm/llms/index.ts @@ -59,6 +59,7 @@ import SambaNova from "./SambaNova"; import Scaleway from "./Scaleway"; import SiliconFlow from "./SiliconFlow"; import Tensorix from "./Tensorix"; +import ApiRoute from "./ApiRoute"; import TARS from "./TARS"; import TestLLM from "./Test"; import TextGenWebUI from "./TextGenWebUI"; @@ -125,6 +126,7 @@ export const LLMClasses = [ xAI, SiliconFlow, Tensorix, + ApiRoute, Scaleway, Relace, Inception, diff --git a/docs/customize/model-providers/more/apiroute.mdx b/docs/customize/model-providers/more/apiroute.mdx new file mode 100644 index 00000000000..90ca4d3bd5a --- /dev/null +++ b/docs/customize/model-providers/more/apiroute.mdx @@ -0,0 +1,93 @@ +--- +title: "API Route" +description: "Configure API Route with Continue to access Claude, GPT, DeepSeek, Gemini, and other models through an aggregated high-concurrency API gateway" +--- + +[API Route](https://www.api-route.com) is an OpenAI-compatible aggregating API gateway that provides high-availability, low-latency access to Claude, OpenAI, DeepSeek, Google Gemini, and other top-tier models with unified billing and developer tooling. + + + You can obtain your API key from the + [API Route Console](https://www.api-route.com/api-keys). + + +## Chat Model + +We recommend configuring **claude-3-7-sonnet-20250219** or **gpt-4o** as your chat model. + + + + ```yaml title="config.yaml" + name: My Config + version: 0.0.1 + schema: v1 + + models: + - name: Claude 3.7 Sonnet + provider: api-route + model: claude-3-7-sonnet-20250219 + apiKey: + roles: + - chat + ``` + + + ```json title="config.json" + { + "models": [ + { + "title": "Claude 3.7 Sonnet", + "provider": "api-route", + "model": "claude-3-7-sonnet-20250219", + "apiKey": "" + } + ] + } + ``` + + + +## Autocomplete Model + + + + ```yaml title="config.yaml" + name: My Config + version: 0.0.1 + schema: v1 + + models: + - name: DeepSeek V3 + provider: api-route + model: deepseek-chat + apiKey: + roles: + - autocomplete + ``` + + + ```json title="config.json" + { + "models": [ + { + "title": "DeepSeek V3", + "provider": "api-route", + "model": "deepseek-chat", + "apiKey": "" + } + ], + "tabAutocompleteModel": { + "title": "DeepSeek V3", + "provider": "api-route", + "model": "deepseek-chat", + "apiKey": "" + } + } + ``` + + + +## Embeddings Model + +API Route provides access to OpenAI and open-weight embedding models (e.g. `text-embedding-3-small`, `text-embedding-3-large`). + +[View the source](https://github.com/continuedev/continue/blob/main/core/llm/llms/ApiRoute.ts) diff --git a/docs/docs.json b/docs/docs.json index b7a1d83f13a..888de3a692d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -105,6 +105,7 @@ { "group": "More Providers", "pages": [ + "customize/model-providers/more/apiroute", "customize/model-providers/more/asksage", "customize/model-providers/more/clawrouter", "customize/model-providers/more/deepseek", diff --git a/extensions/vscode/config_schema.json b/extensions/vscode/config_schema.json index fb3f4c61362..4b29c83dab5 100644 --- a/extensions/vscode/config_schema.json +++ b/extensions/vscode/config_schema.json @@ -236,7 +236,8 @@ "ovhcloud", "venice", "inception", - "tars" + "tars", + "api-route" ], "markdownEnumDescriptions": [ "### OpenAI\nUse gpt-4, gpt-3.5-turbo, or any other OpenAI model. See [here](https://openai.com/product#made-for-developers) to obtain an API key.\n\n> [Reference](https://docs.continue.dev/reference/Model%20Providers/openai)", @@ -289,7 +290,8 @@ "### OVHcloud AI Endpoints is a serverless inference API that provides access to a curated selection of models (e.g., Llama, Mistral, Qwen, Deepseek). It is designed with security and data privacy in mind and is compliant with GDPR. To get started, create an API key on the OVHcloud [AI Endpoints website](https://endpoints.ai.cloud.ovh.net/). For more information, including pricing, visit the OVHcloud [AI Endpoints product page](https://www.ovhcloud.com/en/public-cloud/ai-endpoints/).", "### Venice\n Venice.AI is a privacy-focused generative AI platform, allowing users to interact with open-source LLMs without storing any private user data.\nHosted models support the OpenAI API standard, providing seamless integration for users seeking privacy and flexibility.\nTo get started with the Venice API, either purchase a pro account, stake $VVV for daily inference allotments, or fund your account with USD.\nVisit the [API settings page](https://venice.ai/settings/api) or learn more at the [Venice API documentation](https://venice.ai/api).", "### Inception\n Inception Labs offer a new generation of diffusion-based LLMs.\nVisit the [API settings page](https://platform.inceptionlabs.ai/) or learn more at the [Inception docs](https://platform.inceptionlabs.ai/docs).", - "### TARS\nTARS is an OpenAI-compatible proxy router. To get started, obtain an API key and configure the provider in your config.json." + "### TARS\nTARS is an OpenAI-compatible proxy router. To get started, obtain an API key and configure the provider in your config.json.", + "### API Route\nAPI Route is an enterprise-grade OpenAI-compatible API aggregation platform providing access to Claude 3.7, DeepSeek V3/R1, GPT-4o, Gemini 2.5, Qwen, and more with global routing acceleration.\nTo get started, create an account and get an API key at [api-route.com](https://www.api-route.com).\n> [Models](https://www.api-route.com)" ], "type": "string" }, @@ -2873,7 +2875,8 @@ "tensorix", "function-network", "scaleway", - "ovhcloud" + "ovhcloud", + "api-route" ] }, "model": { @@ -2937,7 +2940,8 @@ "nvidia", "gemini", "siliconflow", - "tensorix" + "tensorix", + "api-route" ] } }, diff --git a/gui/public/logos/apiroute.png b/gui/public/logos/apiroute.png new file mode 100644 index 0000000000000000000000000000000000000000..aff30ce518dc451c2365d3ca11a3697445ebdff9 GIT binary patch literal 27008 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 literal 0 HcmV?d00001 diff --git a/gui/src/pages/AddNewModel/configs/providers.ts b/gui/src/pages/AddNewModel/configs/providers.ts index 9e2aba08c5c..f7f7b57a9fb 100644 --- a/gui/src/pages/AddNewModel/configs/providers.ts +++ b/gui/src/pages/AddNewModel/configs/providers.ts @@ -1270,6 +1270,27 @@ To get started, [register](https://dataplatform.cloud.ibm.com/registration/stepo packages: [{ ...models.AUTODETECT }], apiKeyUrl: "https://app.tensorix.ai", }, + apiroute: { + title: "API Route", + provider: "api-route", + icon: "apiroute.png", + description: + "API Route is an OpenAI-compatible API gateway providing access to Claude, GPT, DeepSeek, Gemini, and more.", + longDescription: + "To get started with API Route, create an account and obtain an API key from [API Route](https://www.api-route.com/api-keys).", + tags: [ModelProviderTags.RequiresApiKey, ModelProviderTags.OpenSource], + collectInputFor: [ + { + inputType: "text", + key: "apiKey", + label: "API Key", + placeholder: "Enter your API Route key", + required: true, + }, + ], + packages: [{ ...models.AUTODETECT }], + apiKeyUrl: "https://www.api-route.com/api-keys", + }, venice: { title: "Venice", provider: "venice", diff --git a/packages/openai-adapters/src/index.ts b/packages/openai-adapters/src/index.ts index 52fb2d33a0c..490719aa609 100644 --- a/packages/openai-adapters/src/index.ts +++ b/packages/openai-adapters/src/index.ts @@ -176,6 +176,8 @@ export function constructLlmApi(config: LLMConfig): BaseLlmApi | undefined { return openAICompatible("https://api.function.network/v1/", config); case "tensorix": return openAICompatible("https://api.tensorix.ai/v1/", config); + case "api-route": + return openAICompatible("https://global.api-route.com/v1/", config); case "openrouter": return new OpenRouterApi(config); case "clawrouter": diff --git a/packages/openai-adapters/src/types.ts b/packages/openai-adapters/src/types.ts index 14b9512f75b..ab72ad7c749 100644 --- a/packages/openai-adapters/src/types.ts +++ b/packages/openai-adapters/src/types.ts @@ -60,6 +60,7 @@ export const OpenAIConfigSchema = BasePlusConfig.extend({ z.literal("zAI"), z.literal("scaleway"), z.literal("tensorix"), + z.literal("api-route"), z.literal("ncompass"), z.literal("relace"), z.literal("huggingface-inference-api"),