Skip to content

AI Router Architecture

WordPress 7.0 introduced the AI Client SDK, enabling plugins and themes to leverage AI capabilities like text generation, image generation, embeddings, and more. However, the SDK presents a challenge: different AI providers excel at different tasks.

  • OpenAI GPT-4 excels at text generation and chat
  • DALL-E / Stable Diffusion specializes in image generation
  • OpenAI Whisper handles speech-to-text
  • Anthropic Claude offers strong reasoning capabilities
  • Local Ollama models provide privacy and cost benefits

Without AI Router, developers must hardcode provider choices or build custom switching logic. AI Router solves this by providing capability-based routing — automatically directing each AI request to the most appropriate provider configuration.

sequenceDiagram
participant App as Plugin/Theme
participant Router as AI Router
participant Map as CapabilityMap
participant Repo as ConfigRepository
participant Provider as AI Provider
App->>Router: AI Request (e.g., text_generation)
Router->>Map: Check explicit mapping
alt Mapping exists
Map-->>Router: Mapped config ID
Router->>Repo: Get config
Repo-->>Router: Configuration
else No mapping
Router->>Repo: Get default config
alt Default supports capability
Repo-->>Router: Default configuration
else Default doesn't support
Router->>Repo: Find any supporting config
alt Found config
Repo-->>Router: Fallback configuration
else No config found
Repo-->>Router: null (use WP default)
end
end
end
Router->>Provider: Route request
Note over Provider: OpenAI, Anthropic,<br/>Azure OpenAI, Ollama
LayerComponents
Admin UIConnectorsIntegration.php, connectors.js
REST APIConfigurationsController.php
Core LogicRouter.php, CapabilityMap.php, ProviderDiscovery.php
DataConfigurationRepository.php, Configuration.php
Storagewp_options
ai-router/
├── src/
│ ├── DTO/
│ │ └── Configuration.php # Immutable config data object
│ ├── Repository/
│ │ ├── ConfigurationRepositoryInterface.php
│ │ └── ConfigurationRepository.php # CRUD for configs
│ ├── Admin/
│ │ └── ConnectorsIntegration.php # Settings → Connectors integration
│ ├── Rest/
│ │ └── ConfigurationsController.php # REST API endpoints
│ ├── CapabilityMap.php # Capability → Config mapping
│ ├── Router.php # Core routing logic
│ └── ProviderDiscovery.php # Discovers installed providers
├── src/js/
│ └── connectors.js # Connectors page UI
└── tests/
├── php/ # PHPUnit + Brain Monkey tests
└── js/ # Vitest + Testing Library tests
  1. Admin UI sends POST /ai-router/v1/configurations
  2. REST controller validates and sanitizes input
  3. Repository saves via update_option()
  4. JSON response returned to UI

The Router::get_configuration_for_capability() method implements the selection algorithm:

  1. Explicit Mapping — If a capability is explicitly mapped to a configuration via the UI’s “Capability Routing” section, use that configuration.

  2. Default Configuration — If no explicit mapping exists, check if the default configuration supports the requested capability.

  3. Best Effort — If no default is set or it doesn’t support the capability, use the first available configuration that supports it.

Configurations:

  • GPT-4 Config (OpenAI) — default, supports text_generation, chat_history
  • Claude Config (Anthropic) — supports text_generation
  • DALL-E Config (OpenAI) — supports image_generation

Routing Results:

  • text_generation → GPT-4 Config (default, supports it)
  • image_generation → DALL-E Config (only one supports it)
  • chat_history → GPT-4 Config (only one supports it)

If Claude Config were set as default instead:

  • text_generation → Claude Config (default, supports it)
  • chat_history → GPT-4 Config (Claude doesn’t support it, fallback)
final readonly class Configuration implements JsonSerializable {
public function __construct(
public string $id, // UUID
public string $name, // Display name
public string $provider_type,// openai, anthropic, azure_openai, etc.
public array $settings, // api_key, endpoint, model, etc.
public array $capabilities, // text_generation, image_generation, etc.
public bool $is_default, // Default fallback flag
) {}
}

The CapabilityMap class manages explicit routing rules stored in wp_options:

// Option: ai_router_capability_map
[
'text_generation' => 'config-uuid-1',
'image_generation' => 'config-uuid-2',
// ... other mappings
]

When a capability has an explicit mapping, that configuration is used regardless of the default setting.

AI Router integrates via WordPress hooks:

// Before AI generation — inject routing
add_action('wp_ai_client_before_generate_result', [$this, 'before_generate'], 5, 2);
// Set up provider authentication
add_action('init', [$this, 'setup_provider_authentication'], 25);

Credential Sync for AI Plugin Compatibility

Section titled “Credential Sync for AI Plugin Compatibility”

The WordPress AI plugin uses has_ai_credentials() to check if valid credentials exist. This function iterates over wp_get_connectors() looking for connectors with non-empty API keys.

Problem: Providers like Azure OpenAI unregister from wp_get_connectors() to provide custom UI, making them invisible to has_ai_credentials(). However, setting the OpenAI connector’s API key option would make the AI Client SDK think OpenAI is configured, leading to wrong provider selection.

Solution: AI Router registers itself as a connector with ID ai_router. The WP_Connector_Registry auto-generates the option name connectors_ai_ai_router_api_key. When AI Router has configurations, it sets this sentinel option to “1”, making has_ai_credentials() return true without making any actual AI provider appear configured.

// In Router::register_connector()
$registry->register('ai_router', [
'name' => 'AI Router',
'description' => __('Capability-based AI provider routing.', 'ai-router'),
'type' => 'ai_provider',
'authentication' => ['method' => 'api_key'],
]);
// In ConfigurationRepository::sync_connector_option()
// Uses auto-generated option name: connectors_ai_ai_router_api_key
update_option('connectors_ai_ai_router_api_key', '1');

This ensures:

  1. has_ai_credentials() returns true (AI plugin features work)
  2. OpenAI provider doesn’t appear configured (won’t be incorrectly selected)
  3. Azure and other providers get their actual credentials synced separately
EndpointMethodDescription
/ai-router/v1/configurationsGETList all configurations
/ai-router/v1/configurationsPOSTCreate configuration
/ai-router/v1/configurations/{id}GETGet single configuration
/ai-router/v1/configurations/{id}PUTUpdate configuration
/ai-router/v1/configurations/{id}DELETEDelete configuration
/ai-router/v1/capability-mapGETGet capability mappings
/ai-router/v1/capability-mapPOSTUpdate capability mappings
/ai-router/v1/defaultGETGet default configuration ID

AI Router supports all WordPress 7.0 AI Client SDK capabilities:

CapabilityDescription
text_generationGenerate text responses (GPT, Claude, etc.)
chat_historyMaintain conversation context
image_generationGenerate images (DALL-E, Stable Diffusion)
embedding_generationCreate vector embeddings
text_to_speech_conversionConvert text to audio
speech_generationGenerate speech/audio
music_generationGenerate music
video_generationGenerate video content
// Override configuration selection
add_filter('ai_router_get_configuration', function($config, $capability) {
// Custom logic
return $config;
}, 10, 2);
// Modify fallback configuration
add_filter('ai_router_fallback_config', function($config, $capability) {
// Custom fallback logic
return $config;
}, 10, 2);
// After routing decision is made
add_action('ai_router_routed', function($config, $capability, $prompt_builder) {
// Logging, analytics, etc.
}, 10, 3);
  • All REST endpoints require manage_options capability
  • API keys are stored encrypted in wp_options (when using core’s encryption)
  • Settings are sanitized via registered sanitize callbacks
  • Nonces protect admin UI operations
  • Priority/Weight System — Allow ordering when multiple configs support a capability
  • Load Balancing — Distribute requests across multiple providers
  • Cost Tracking — Monitor API usage and costs per provider
  • Health Checks — Automatic failover when a provider is unavailable
  • Rate Limiting — Per-provider rate limit management