How to Add a Custom OpenAI-Compatible Provider to OmniRoute
You add a custom OpenAI-compatible provider to OmniRoute by creating a RegistryEntry module in open-sse/config/providers/registry/ that sets format: "openai", registering it in the exported REGISTRY map, and allowing the default executor to handle request construction and authentication automatically.
OmniRoute discovers every LLM endpoint through its centralized Provider Registry (open-sse/config/providerRegistry.ts). Each registry entry describes the provider's API format, authentication method, base URLs, and model catalogue, enabling the routing engine to treat any OpenAI-compatible service as a first-class citizen for combo routing and fallback logic.
Understanding the Provider Registry Architecture
The Provider Registry serves as the single source of truth for all LLM endpoints in OmniRoute. Located at open-sse/config/providerRegistry.ts, this system maintains a REGISTRY map that associates provider IDs with their configuration entries. Lookup helpers such as getRegistryEntry and getRegisteredProviders consume this registry to resolve routing decisions, validate authentication schemes, and determine if a provider uses an authoritative live catalog.
Each provider entry follows the RegistryEntry interface, which specifies the API format—such as "openai" for OpenAI-compatible endpoints—the base URL, chat completion path, headers, and available models. This declarative approach means you can integrate a new service without modifying the core routing logic, provided it conforms to the OpenAI chat-completions specification.
Step 1: Create the Registry Module
Create a new folder under open-sse/config/providers/registry/ to house your provider definition. For example, create my-custom/ containing an index.ts file that exports a RegistryEntry object. This entry must declare format: "openai" to signal that the endpoint follows the OpenAI chat-completions API structure.
// open-sse/config/providers/registry/my-custom/index.ts
import type { RegistryEntry } from "../shared.ts";
export const myCustomProvider: RegistryEntry = {
id: "my-custom",
format: "openai", // Signals OpenAI-compatible format
authType: "apikey", // Uses Bearer token in Authorization header
baseUrl: "https://api.my-custom.com", // Service base URL
chatPath: "/v1/chat/completions", // Standard OpenAI endpoint path
headers: { "Content-Type": "application/json" },
requestDefaults: { timeoutMs: 30_000 },
models: [
{
id: "gpt-custom-1",
contextLength: 8192,
// Optional: capabilities, pricing, etc.
},
],
};
Step 2: Register in the Central Index
Expose your module by importing it into open-sse/config/providers/registry/index.ts and adding it to the exported REGISTRY record. This registration makes the provider available to the routing system and model discovery endpoints.
// open-sse/config/providers/registry/index.ts
import { myCustomProvider } from "./my-custom/index.ts";
export const REGISTRY: Record<string, RegistryEntry> = {
// ...existing providers
"my-custom": myCustomProvider,
};
Step 3: Leverage the Default Executor
Because your provider uses the standard OpenAI format, you do not need to write custom execution logic. The default executor at open-sse/executors/default.ts automatically constructs requests, attaches the Bearer token from the authType: "apikey" configuration, and forwards responses unchanged. This executor handles streaming and non-streaming completions according to the OpenAI specification.
You only need a custom executor if your provider exhibits non-standard behavior, such as unique streaming quirks or proprietary authentication flows. For standard OpenAI-compatible endpoints, the default implementation suffices.
Step 4: Define Available Models
Populate the models array in your registry entry to expose the provider's capabilities via the /v1/models route. Each model object includes an id, contextLength, and optional metadata such as capabilities or pricing. This metadata enables combo routing to select appropriate models based on context window requirements or cost constraints.
models: [
{
id: "gpt-custom-1",
contextLength: 8192,
pricing: { prompt: 0.001, completion: 0.002 }
},
{
id: "gpt-custom-2",
contextLength: 32768,
}
]
Step 5: Write Unit Tests
Validate your integration by copying the test pattern from existing OpenAI-style provider tests, such as tests/unit/openai-style-providers-4239-4155-3841.test.ts. Your tests should verify that the registry entry exists, that format equals "openai", and that baseUrl and chatPath resolve to valid URLs. This satisfies OmniRoute's mandatory test-coverage requirements and prevents regression.
Example test assertions:
- Verify
REGISTRY["my-custom"]is defined - Assert
REGISTRY["my-custom"].format === "openai" - Check that
new URL(REGISTRY["my-custom"].chatPath, REGISTRY["my-custom"].baseUrl)is valid
Step 6: Run the Full Test Suite
Execute npm run test:unit and npm run test:vitest to ensure your provider does not break combo routing, resilience layers, or translation mechanisms. All existing tests must pass before your provider can be considered safely integrated.
Step 7: Document the Provider
Add a concise entry to the auto-generated provider reference at docs/reference/PROVIDER_REFERENCE.md or your internal knowledge base. Link directly to your registry source file (open-sse/config/providers/registry/my-custom/index.ts) so administrators can review configuration details.
Critical Source Files
| File | Purpose |
|---|---|
open-sse/config/providerRegistry.ts |
Defines the RegistryEntry interface and lookup helpers like getRegistryEntry and providerUsesAuthoritativeLiveCatalog. |
open-sse/config/providers/registry/index.ts |
Central export point that constructs the REGISTRY map imported by the routing engine. |
open-sse/config/providers/registry/openai/index.ts |
Reference implementation showing the exact shape required for OpenAI-compatible entries. |
open-sse/executors/default.ts |
Generic executor that handles request building and authentication for format: "openai" providers. |
Summary
- Create a new folder under
open-sse/config/providers/registry/containing anindex.tsthat exports aRegistryEntrywithformat: "openai". - Register the provider in
open-sse/config/providers/registry/index.tsby importing it and adding it to theREGISTRYmap. - Rely on
open-sse/executors/default.tsto handle request construction and Bearer token authentication automatically. - Define models in the entry's
modelsarray to enable discovery via/v1/modelsand combo routing. - Test using the pattern in
tests/unit/openai-style-providers-4239-4155-3841.test.tsand runnpm run test:unitto verify integration. - Document the provider in
docs/reference/PROVIDER_REFERENCE.mdwith a link to the source configuration.
Frequently Asked Questions
What authentication methods does OmniRoute support for custom providers?
OmniRoute supports multiple authentication schemes through the authType field in the registry entry. For OpenAI-compatible providers, you typically set authType: "apikey", which instructs the default executor to attach a Bearer token in the Authorization header. Other supported types may include custom header-based authentication, depending on the executor implementation.
Do I need to write custom code to handle streaming responses?
No. If your provider follows the standard OpenAI chat-completions format and you set format: "openai" in the registry entry, the default executor at open-sse/executors/default.ts automatically handles both streaming and non-streaming responses. It manages the Server-Sent Events (SSE) format and forwards the stream unchanged to the client.
How does OmniRoute discover the models available from my custom provider?
OmniRoute exposes models through the /v1/models endpoint based on the models array defined in your RegistryEntry. Each object in this array must include at least an id and contextLength. The routing system uses this metadata for combo routing decisions, matching requests to appropriate models based on context window requirements and other capabilities.
Can I use environment variables for the base URL or API keys?
Yes. While the registry entry defines static configuration in open-sse/config/providers/registry/my-custom/index.ts, you can import environment variables at the module level to set baseUrl or other configuration values. The registry file is standard TypeScript, allowing you to externalize sensitive values or deployment-specific URLs using your runtime's environment variable API.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →