How to Add a New LLM Provider to the OmniRoute Registry
To add a new LLM provider to OmniRoute, create a RegistryEntry definition in open-sse/config/providers/registry/<provider-id>/index.ts, export it from the barrel file open-sse/config/providers/index.ts, and verify it with a unit test.
OmniRoute maintains a centralized provider registry that powers routing, resilience, and UI components across the entire stack. According to the diegosouzapw/OmniRoute source code, all LLM providers are registered in open-sse/config/providerRegistry.ts, which aggregates definitions from the modules exported in open-sse/config/providers/. This guide walks through the exact implementation steps used in the codebase.
Overview of the Provider Registry Architecture
The registry serves as the single source of truth for provider metadata. The REGISTRY object in providerRegistry.ts (lines 6-12) is built from all exports in the providers barrel file. Functions like getRegistryEntry (lines 77-81) and generateModels dynamically resolve providers at runtime.
Any component needing provider data—whether the routing engine, health checks, or model selection UI—reads from this unified registry. A correctly-shaped entry makes a new provider instantly available throughout the stack without additional configuration.
Step-by-Step Guide to Adding a Provider
Create the Provider Directory
Create a new folder under open-sse/config/providers/registry/ using your provider's ID as the directory name. For example, open-sse/config/providers/registry/myai/.
This directory name becomes the canonical identifier for your provider across the codebase.
Define the RegistryEntry in index.ts
Create open-sse/config/providers/registry/myai/index.ts with a complete RegistryEntry export:
import { RegistryEntry, RegistryModel } from "../../shared.ts";
/* Define available models */
export const MYAI_MODELS: RegistryModel[] = [
{
id: "myai/gpt-4-mini",
contextLength: 8192,
},
{
id: "myai/gpt-4",
contextLength: 32768,
},
];
/* Export the provider entry */
const myProvider: RegistryEntry = {
id: "myai",
alias: "myai",
format: "openai",
baseUrl: "https://api.myai.com/v1",
chatPath: "/chat/completions",
authType: "apikey",
requestDefaults: { headers: { Authorization: "Bearer $API_KEY" } },
models: MYAI_MODELS,
passthroughModels: false,
};
export default myProvider;
Required RegistryEntry fields include:
id— Provider identifier matching the directory nameformat— Request/response format ("openai","anthropic", etc.)baseUrl— Root endpoint for API callsauthType— Either"apikey"or"oauth"models— Array ofRegistryModelobjects withidandcontextLength
Export from the Providers Barrel
Add your export to open-sse/config/providers/index.ts:
// Existing re-exports
export * from "./shared.ts";
// Add your provider
export { default as myai } from "./registry/myai/index.ts";
The REGISTRY export in providerRegistry.ts automatically aggregates all barrel exports, so no additional registration step is needed.
Write a Unit Test
Create tests/unit/myai-provider.test.ts to satisfy the mandatory test-coverage rule:
import { assert } from "node:assert";
import { REGISTRY } from "../../open-sse/config/providerRegistry.ts";
test("myai provider is registered", () => {
const entry = REGISTRY.myai;
assert.ok(entry, "REGISTRY.myai must be defined");
assert.deepEqual(entry.models?.map((m) => m.id), [
"myai/gpt-4-mini",
"myai/gpt-4",
]);
});
Reference existing provider tests in tests/unit/ for validation patterns.
Run Quality Checks
Execute the repository's linting and type-checking commands:
npm run lint
npm run typecheck:core
The codebase enforces 2-space indentation and explicit TypeScript types. Fix any violations before committing.
Commit via Isolated Work-Tree
Follow OmniRoute's work-tree policy: create an isolated work-tree, commit only changed files, push to a branch, and open a pull request. Direct commits to main are prohibited.
Key Files and Their Roles
| Purpose | Path |
|---|---|
| Central registry export and helper functions | open-sse/config/providerRegistry.ts |
| Provider-specific definitions | open-sse/config/providers/registry/ |
| Barrel file aggregating all providers | open-sse/config/providers/index.ts |
Shared types (RegistryEntry, RegistryModel) |
open-sse/config/providers/shared.ts |
| Unit test location | tests/unit/<provider>-provider.test.ts |
AuthType and Authentication Configuration
The authType field determines how OmniRoute handles credentials:
"apikey"— Uses static API keys injected into headers viarequestDefaults"oauth"— Triggers OAuth flow with token refresh handling
For API key authentication, reference the key with $API_KEY in requestDefaults. The routing engine substitutes this with the actual credential at request time.
Verifying Your Provider Registration
After completing the steps above, verify integration using getRegistryEntry from providerRegistry.ts:
import { getRegistryEntry } from "./open-sse/config/providerRegistry.ts";
const entry = getRegistryEntry("myai");
console.log(entry.baseUrl); // "https://api.myai.com/v1"
This utility (lines 77-81) validates that your provider appears in the runtime REGISTRY and returns the complete RegistryEntry object.
Summary
- Create
open-sse/config/providers/registry/<id>/index.tswith a validRegistryEntryexport - Add the provider export to
open-sse/config/providers/index.ts - Write a unit test under
tests/unit/asserting registry presence - Run
npm run lintandnpm run typecheck:corebefore committing - Use isolated work-trees for all commits; open pull requests for review
Once merged, the new LLM provider becomes discoverable by OmniRoute's routing engine, health checks, and model selection interfaces.
Frequently Asked Questions
What file format should my provider implement?
Your provider's format field in RegistryEntry specifies the request/response protocol. OmniRoute supports "openai" for OpenAI-compatible APIs, "anthropic" for Claude-style endpoints, and other formats as defined in shared.ts. The routing engine uses this field to transform requests appropriately.
Why must I export from both the directory file and the barrel file?
The REGISTRY object in providerRegistry.ts is constructed from the aggregated exports of open-sse/config/providers/index.ts. Exporting only from your registry/<provider>/index.ts file leaves the provider invisible to the central registry. The barrel pattern ensures all providers are collected in a single import location.
How do I handle providers with dynamic model lists?
Set passthroughModels: true in your RegistryEntry to bypass static model validation. This allows the routing engine to accept any model ID from that provider without pre-registration. Use this for providers that frequently add or rotate models.
Where does the $API_KEY placeholder get resolved?
The routing engine in open-sse/ substitutes $API_KEY with actual credentials from the configured secret store at request time. Never hardcode real API keys in registry definitions—always use the placeholder syntax with requestDefaults.
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 →