How 5ire Abstracts Multiple AI Providers Through a Unified Interface

5ire abstracts multiple AI providers through a unified interface by treating every AI service as a provider object implementing the IServiceProvider contract, enabling seamless switching between OpenAI, Azure, Anthropic, and custom endpoints without modifying core chat logic.

Managing heterogeneous AI backends in a single application often fragments code into provider-specific implementations. The open-source project nanbingxyz/5ire solves this by abstracting multiple AI providers through a unified interface, allowing developers to interact with OpenAI, Azure, Anthropic, Ollama, and custom self-hosted APIs using identical patterns. This architecture centers on a strict provider contract, a centralized registry, and generic chat services that operate on normalized configuration objects.

The Provider Contract: Defining the Unified Interface

IServiceProvider Interface Structure

The foundation of 5ire's abstraction layer resides in src/providers/types.ts, which defines the IServiceProvider interface. This contract standardizes how every AI service is represented, regardless of its underlying API differences. The interface includes properties for the provider name, API base URL, optional authentication key, pricing details, and a complete chat model configuration object. By enforcing this structure, 5ire ensures that any component consuming a provider can expect consistent fields for building requests and handling responses.

Concrete Provider Implementations

Static Metadata Pattern

Each supported AI service implements the IServiceProvider contract as a static metadata object exported from its own file. For example, src/providers/OpenAI.ts exports a plain JavaScript object that satisfies the interface, containing the default API base URL (https://api.openai.com/v1), available model lists, capability flags, and default parameters. Similarly, src/providers/Azure.ts, src/providers/Anthropic.ts, and src/providers/Ollama.ts follow this identical pattern, each containing only static configuration data without business logic.

The Provider Registry

The src/providers/index.ts file functions as the central registry, re-exporting every built-in provider in a mapped object called providers. This module exposes two critical helper functions: getBuiltInProvider, which retrieves a provider configuration by its ProviderType identifier, and getChatAPISchema, which returns the appropriate API schema for chat completions. By funneling all provider access through this registry, the application can look up any AI service by name without hardcoding file paths or import statements throughout the codebase.

Runtime Provider Management

Merging Built-in and Custom Providers

The src/stores/useProviderStore.ts module handles runtime provider state by merging the built-in registry with user-defined configurations added at runtime. This store normalizes provider fields, ensuring that custom providers added at runtime conform to the same IServiceProvider structure as built-in ones. It exposes selectors such as getAvailableProvider, getAvailableModel, and getGroupedModelOptions, which the UI and chat services use to populate dropdown menus and validate selections. The store also manages persistence, saving custom provider configurations between sessions.

Provider Readiness and Validation

Before initiating chat requests, the store validates provider readiness by checking for required fields. For each provider instance, it verifies that the API base URL is valid and that an API key is present if the provider requires authentication. This validation layer prevents runtime errors by ensuring that only properly configured providers are exposed to the chat services, regardless of whether they are built-in services like OpenAI or custom self-hosted endpoints.

Unified Chat Service Architecture

The Base Service Contract

All chat implementations adhere to the IChatService interface defined in src/intellichat/services/IChatService.ts. This contract specifies generic methods for sending messages, handling streaming responses, and managing conversation context. By programming against this interface rather than concrete implementations, the core application logic remains agnostic to whether the underlying provider uses OpenAI's /chat/completions endpoint, Anthropic's Messages API, or Azure's deployment-specific URLs.

Provider-Specific Service Implementations

Concrete services such as OpenAIChatService.ts, AzureChatService.ts, and AnthropicChatService.ts extend a base NextChatService class, receiving the provider configuration object via their constructors. These implementations handle provider-specific quirks—such as Azure's deployment naming conventions or Anthropic's message formatting—while delegating common tasks like URL construction, header generation (Authorization: Bearer …), and payload serialization to shared utilities. This architecture ensures that adding support for a new provider requires only implementing the specific request/response mapping, without duplicating connection management or retry logic.

Code Examples

Retrieving a Provider Configuration

To access a provider's settings from the unified store, use the getAvailableProvider selector:

import useProviderStore from '@/stores/useProviderStore';

// Get the default (or a specific) provider configuration
const provider = useProviderStore.getState().getAvailableProvider('OpenAI');

// provider now contains:
// { name: 'OpenAI', apiBase: 'https://api.openai.com/v1', apiKey: '', … }

Instantiating a Chat Service

Create a chat service instance by combining the provider configuration with a chat context:

import OpenAIChatService from '@/intellichat/services/OpenAIChatService';
import { createChatContext } from '@/intellichat/types';

// Build a chat context (model, temperature, etc.)
const context = createChatContext({
  provider,
  model: provider.chat.models[0],   // e.g. gpt‑4o
});

// Instantiate the service – the constructor receives the provider object
const chatService = new OpenAIChatService('myChat', context);

// Send a message
chatService.chat({
  message: 'Explain quantum entanglement in plain English.',
  onMessage: (partial) => console.log('Δ', partial),
  onComplete: (result) => console.log('✅', result),
  onError: (err) => console.error('❌', err),
});

Adding a Custom Provider at Runtime

Extend the system with custom endpoints without modifying source code:

import useProviderStore from '@/stores/useProviderStore';

// Define a new provider (e.g., a self‑hosted OpenAI‑compatible API)
const custom = {
  name: 'MyOpenAI',
  apiBase: 'http://localhost:8000/v1',
  apiKey: 'my-secret-key',
  currency: 'USD',
  isDefault: false,
  models: [],            // optional: pre‑populate local models
};

// Persist the custom provider and merge it with built‑ins
useProviderStore.getState().createProvider();           // creates a blank entry
useProviderStore.getState().updateProvider('MyOpenAI', custom);

Summary

  • IServiceProvider interface – The src/providers/types.ts file defines a strict contract that every AI service must implement, ensuring consistent fields for API endpoints, authentication, and model configurations.
  • Static provider metadata – Each supported service (OpenAI, Azure, Anthropic, Ollama) exports a plain configuration object from its own file in src/providers/, containing only static data without business logic.
  • Centralized registry – src/providers/index.ts aggregates all built‑in providers into a map and exposes lookup helpers like getBuiltInProvider, decoupling the application from specific import paths.
  • Runtime store management – src/stores/useProviderStore.ts merges built‑in and custom providers, validates readiness (URL and API key), and exposes selectors such as getAvailableProvider and getAvailableModel.
  • Generic chat services – All chat implementations adhere to the IChatService interface and receive provider configuration via the NextChatService base class, allowing provider‑specific quirks to be handled while sharing common request‑building logic.

Frequently Asked Questions

What is the IServiceProvider interface in 5ire?

The IServiceProvider interface is the core contract defined in src/providers/types.ts that standardizes how every AI service is represented within the application. It specifies required properties including the provider name, API base URL, optional authentication key, pricing currency, and a complete chat model configuration object, ensuring that any component interacting with a provider can rely on a consistent data structure regardless of whether it is OpenAI, Azure, or a custom endpoint.

How does 5ire handle custom AI providers that are not built‑in?

5ire handles custom providers through the useProviderStore module located in src/stores/useProviderStore.ts, which merges built‑in providers with user‑defined configurations added at runtime. Users can define new providers by specifying a name, API base URL, and authentication credentials, then persist them using the createProvider and updateProvider store methods. The store validates these custom entries against the same IServiceProvider interface used for built‑in services, ensuring they integrate seamlessly with the chat services and UI components.

Can I switch between different AI providers without changing the chat logic?

Yes, the architecture explicitly supports switching between providers without modifying core chat logic. The IChatService interface in src/intellichat/services/IChatService.ts defines a generic contract that all chat implementations follow, while concrete services like OpenAIChatService or AnthropicChatService extend the base NextChatService class and receive provider configuration through their constructors. Because the services operate on the normalized IServiceProvider object and share common request‑building logic, changing from OpenAI to Azure or to a custom provider only requires selecting a different provider from the store, leaving the chat invocation code unchanged.

Where are the built‑in AI providers registered in the 5ire codebase?

Built‑in providers are registered in the central registry located at src/providers/index.ts. This file imports the static configuration objects from individual provider files (such as OpenAI.ts, Azure.ts, and Anthropic.ts) and aggregates them into a providers map object. It also exports helper functions including getBuiltInProvider for retrieving a specific provider by its ProviderType identifier and getChatAPISchema for resolving API schemas, effectively decoupling the rest of the application from the specific file locations of each provider implementation.

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 →