# How to Add a New LLM Provider to the OmniRoute Registry

> Learn how to add a new LLM provider to the OmniRoute registry. Follow these simple steps to integrate new LLM services into your routing configuration.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-19

---

**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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providers/registry/myai/index.ts) with a complete `RegistryEntry` export:

```typescript
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 name
- `format` — Request/response format (`"openai"`, `"anthropic"`, etc.)
- `baseUrl` — Root endpoint for API calls
- `authType` — Either `"apikey"` or `"oauth"`
- `models` — Array of `RegistryModel` objects with `id` and `contextLength`

### Export from the Providers Barrel

Add your export to [`open-sse/config/providers/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providers/index.ts):

```typescript
// 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/tests/unit/myai-provider.test.ts) to satisfy the mandatory test-coverage rule:

```typescript
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:

```bash
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts) |
| Provider-specific definitions | `open-sse/config/providers/registry/` |
| Barrel file aggregating all providers | [`open-sse/config/providers/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providers/index.ts) |
| Shared types (`RegistryEntry`, `RegistryModel`) | [`open-sse/config/providers/shared.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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 via `requestDefaults`
- **`"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`](https://github.com/diegosouzapw/OmniRoute/blob/main/providerRegistry.ts):

```typescript
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.ts` with a valid `RegistryEntry` export
- Add the provider export to [`open-sse/config/providers/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providers/index.ts)
- Write a unit test under `tests/unit/` asserting registry presence
- Run `npm run lint` and `npm run typecheck:core` before 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/providerRegistry.ts) is constructed from the aggregated exports of [`open-sse/config/providers/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`.