How Bella OpenAPI Implements the Protocol Adapter Pattern for AI Provider Routing

Bella OpenAPI isolates every AI provider behind a unified IProtocolAdaptor contract, using a central AdaptorManager registry and Spring auto-configuration to route requests without modifying core controller logic.

The lianjiatech/bella-openapi repository demonstrates a clean protocol adapter pattern implementation that decouples the HTTP request pipeline from vendor-specific AI provider APIs. By enforcing a standard adapter interface and automating registration through Spring Boot, the system enables zero-code changes when adding new LLM providers like OpenAI, Azure, or custom endpoints.

Core Components of the Protocol Adapter Pattern

The IProtocolAdaptor Contract

At the heart of the system lies the IProtocolAdaptor interface located in [api/server/src/main/java/com/ke/bella/openapi/protocol/IProtocolAdaptor.java](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/IProtocolAdaptor.java). This contract mandates four critical capabilities that every provider must expose:

  • endpoint() – Returns the API path segment (e.g., "chat/completions") this adapter handles.
  • getDescription() – Provides a human-readable label for UI and documentation generation.
  • getPropertyClass() – Declares the specific DTO class used to deserialize request bodies (e.g., CompletionProperty).
  • Helper methods – Standardized utilities for authentication header construction and large-object cleanup.

Concrete Adaptor Interfaces

Specific AI capabilities extend the base contract through typed sub-interfaces. For example, [CompletionAdaptor.java](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/completion/CompletionAdaptor.java) narrows the generic contract to completion-specific request properties:

package com.ke.bella.openapi.protocol.completion;

import com.ke.bella.openapi.protocol.IProtocolAdaptor;
import com.ke.bella.openapi.protocol.CompletionProperty;

public interface CompletionAdaptor<T extends CompletionProperty> extends IProtocolAdaptor {
    // Implementation provides request-building logic for completion endpoints
}

This inheritance strategy allows the system to maintain type safety while supporting diverse operation types (embeddings, chat, image generation) under the same routing umbrella.

The AdaptorManager Registry

The [AdaptorManager.java](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/AdaptorManager.java) class functions as a global singleton registry maintaining a nested map structure: endpoint → protocol → adaptor instance. It exposes three primary operations:

  • getProtocolAdaptor(String endpoint, String protocol) – Retrieves the concrete adapter for a specific provider protocol.
  • support(String endpoint, String protocol) – Boolean check verifying whether a protocol adapter exists for the given endpoint.
  • getProtocolAdaptors(String endpoint) – Returns all registered adapters for an endpoint, used for capability discovery.

Spring Auto-Configuration with BellaAutoConf

Registration occurs automatically at startup via [BellaAutoConf.java](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java). This configuration class autowires every IProtocolAdaptor bean discovered in the classpath and injects them into the AdaptorManager:

@Configuration
public class BellaAutoConf {

    @Bean
    public AdaptorManager adaptorManager(@Autowired List<IProtocolAdaptor> adaptors) {
        AdaptorManager manager = AdaptorManager.getInstance();
        adaptors.forEach(adaptor -> manager.register(adaptor.endpoint(), adaptor));
        return manager;
    }
}

This design eliminates manual registration; adding a new provider requires only implementing the interface and annotating the class with Spring's @Component.

Runtime Request Routing Flow

When a client sends a request to /v1/chat/completions, the following sequence executes:

  1. Controller Receipt – The Spring controller receives the HTTP request after security interceptors validate API keys and quotas.

  2. Channel Selection – [ChannelRouter.java](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/ChannelRouter.java) queries available channels (provider instances) and filters them using AdaptorManager.getInstance().support(endpoint, channel.getProtocol()). Only channels with registered protocol adapters proceed.

  3. Adaptor Resolution – The router returns a ChannelDB object, and the controller fetches the concrete implementation:

    IProtocolAdaptor adaptor = adaptorManager.getProtocolAdaptor(
            channel.getEndpoint(), 
            channel.getProtocol()
    );
  4. Request Construction – The controller uses adaptor.getPropertyClass() to deserialize the JSON body into the correct DTO (e.g., OpenAICompletionProperty), then invokes the adapter's builder methods to create an okhttp3.Request with proper authentication headers.

  5. Execution – The adapter executes the provider-specific HTTP call, and the system handles response streaming, cost accounting, and metrics downstream.

Adding a New AI Provider

Extending the system to support a new AI service requires three steps with zero changes to existing routing logic:

  1. Create the Implementation Class

    @Component
    public class AnthropicCompletionAdaptor implements CompletionAdaptor<AnthropicProperty> {
        
        @Override
        public String endpoint() {
            return "chat/completions";
        }
        
        @Override
        public String getDescription() {
            return "Anthropic Claude Chat Completion";
        }
        
        @Override
        public Class<?> getPropertyClass() {
            return AnthropicProperty.class;
        }
        
        // Provider-specific request building logic here
    }
  2. Define the Property DTO – Create AnthropicProperty extending CompletionProperty to handle Anthropic's unique request fields.

  3. Deploy – Spring's component scanning automatically picks up the @Component annotation, BellaAutoConf registers it with AdaptorManager, and the ChannelRouter immediately begins routing compatible requests to the new provider.

Summary

  • IProtocolAdaptor defines the mandatory contract for all provider integrations, standardizing endpoint names, descriptions, and property classes.
  • AdaptorManager maintains a thread-safe registry mapping endpoints and protocols to concrete adapter instances.
  • BellaAutoConf automates adapter discovery and registration using Spring's dependency injection container.
  • ChannelRouter enforces protocol compatibility at runtime, filtering channels based on AdaptorManager.support() checks.
  • Zero-code integration is achieved for new providers by implementing the interface and declaring a Spring bean.

Frequently Asked Questions

What is the protocol adapter pattern in Bella OpenAPI?

The protocol adapter pattern in Bella OpenAPI is an architectural design that isolates vendor-specific AI provider implementations behind a common interface (IProtocolAdaptor). This allows the core routing and controller layers to remain agnostic of whether the underlying provider is OpenAI, Azure, or a custom LLM endpoint, enabling seamless provider switching and addition without modifying business logic.

How does the system decide which AI provider handles a request?

The ChannelRouter class decides by first retrieving a list of candidate channels (provider instances) that meet safety, quota, and load-balancing criteria. It then validates each channel against AdaptorManager.support(endpoint, channel.getProtocol()) to ensure a registered adapter exists for that provider's protocol. The first valid channel is selected, and its associated adapter is retrieved via adaptorManager.getProtocolAdaptor() to handle the request.

Can I add a custom AI provider without modifying existing code?

Yes. You only need to create a new class implementing IProtocolAdaptor (or a specialized sub-interface like CompletionAdaptor), annotate it with @Component, and ensure it is on the classpath. Spring Boot's auto-configuration in BellaAutoConf automatically registers the adapter with the AdaptorManager at startup, making it available for routing immediately.

Where is the adapter registry stored and queried?

The adapter registry is stored as a concurrent map inside the AdaptorManager singleton class, mapping endpoint strings to protocol strings to adapter instances. Controllers and routers query this registry at runtime using getProtocolAdaptor() to retrieve the correct implementation for request building, or getProtocolAdaptors() to list available protocols for documentation and frontend discovery via EndpointService.

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 →