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

// 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 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:

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
  • 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. 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →