Opened 7 weeks ago
Last modified 3 weeks ago
#65358 new enhancement
AI Provider Priority and Fallback
| Reported by: | georgestephanis | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | AI | Version: | 7.0 |
| Severity: | normal | Keywords: | ai-client |
| Cc: | Focuses: |
Description
AI Disclosure: While I found and have been exploring this issue, I've leveraged LLMs such as Claude and Copilot to aid in detailing the intricacies of a new API and libraries and to aid in trying to make my ramblings more intelligible.
WordPress 7.0 introduced a Connectors API and a Settings > Connectors screen that lets site owners connect multiple AI providers (OpenAI, Anthropic, Google, and third-party plugins). However, the underlying AI client (php-ai-client) has no way to honour a site owner's preference about which provider to use first, and no way to automatically try the next provider when the chosen one fails. The result is that provider selection is effectively random from the site owner's perspective, and a single provider outage or rate-limit error produces a hard failure even when other connected providers could fulfil the request.
This ticket proposes two related changes to WordPress core:
- A filter that lets plugins express a preferred provider order.
- Automatic fallback to the next provider in that order when generation fails.
## Background: how the AI client selects a provider today
When WordPress (or a plugin) calls wp_ai_client_prompt(), it returns a WP_AI_Client_Prompt_Builder. Calling ->generate_text() (or any other generation method) on that builder triggers the following sequence inside PromptBuilder::generateResult():
getConfiguredModel()callsProviderRegistry::findModelsMetadataForSupport()to discover every registered provider/model pair that meets the capability requirements.findModelsMetadataForSupport()iterates$this->registeredIdsToClassNames— a plain PHP array whose insertion order equals the order in which AI provider plugins registered themselves, which in practice equals plugin-activation order.- The first matching provider/model in that list is selected. No filter is applied; there is no concept of "preferred" provider at this layer.
executeModelGeneration()calls the chosen model directly. There is no try/catch around the actual API call: if the provider returns a rate-limit error, an authentication failure, or a service outage, the exception propagates immediately to the caller. No other provider is tried.
The ai core plugin adds a partial workaround for features that extend Abstract_Ability: three filters (wpai_preferred_text_models, wpai_preferred_image_models, wpai_preferred_vision_models) let plugins reorder the [provider, model] preference list that is passed to ->usingModelPreference(). This covers those features only. Any code that calls wp_ai_client_prompt() directly — including core itself and third-party plugins that do not depend on the ai plugin — bypasses these filters entirely.
## Problem 1 — No user-configurable provider priority
### Current behaviour
A site with OpenAI, Anthropic, and Google all connected has no way to tell WordPress "prefer Anthropic for all AI features." The provider that was activated first wins every time. Plugin deactivation/reactivation order, bulk-activation order, or a hosting environment that activates plugins in filesystem order can all silently change which provider is used.
### User impact
- Cost control: a site owner may have a cheaper or free-tier provider they want tried first, falling back to a more expensive one only if needed.
- Quality control: different providers have different strengths; a site owner may strongly prefer one model for writing tasks and another for image generation.
- Compliance / data residency: some organisations must route data through a specific provider for legal reasons. Activation order gives them no guarantee.
- Predictability: when AI-generated output changes unexpectedly, the root cause is often a silent provider switch. There is currently no way to lock a preference without writing custom code.
## Problem 2 — No automatic fallback when a provider fails
### Current behaviour
Once PromptBuilder has selected a provider, it calls the provider's generation method directly inside executeModelGeneration(). The call is not wrapped in any error handling. A runtime exception — caused by a rate-limit response, an expired API key, a provider outage, a network timeout, or a quota exhaustion — propagates immediately to the caller as an unhandled exception.
No other provider is tried, even if multiple connected providers could fulfil exactly the same request.
### User impact
- Silent feature failures: an excerpt-generation button returns an error to the editor even though two other connected and working providers exist on the site.
- Rate limits become site-wide outages: hitting an API rate limit on the primary provider disables all AI features for every user on the site until the limit resets, even if a secondary provider is available.
- Reliability expectation gap: site owners who connect multiple providers reasonably expect that doing so provides redundancy. It does not today.
- No cost-aware routing: there is no way to attempt a cheaper provider, accept failure only from that one, and escalate to a more expensive provider — a common pattern in production AI applications.
#### Important design considerations
- Only runtime failures trigger fallback. Configuration errors (
InvalidArgumentException) — e.g. an unsupported capability — should still propagate immediately. Falling back to a different provider will not fix a misconfigured prompt. - Fallback should be opt-in or clearly documented. Some callers may not want silent fallback (e.g. a feature that explicitly requires a specific provider's output format). A filter such as
wp_ai_provider_fallback_enabled(defaultingtrue) would let callers disable it when needed. - An action hook on provider failure (
wp_ai_provider_failed) would allow monitoring plugins to surface repeated failures to the site admin, which is valuable operational feedback independently of the priority feature.
## How these two changes interact
Priority and fallback are independent features that compose naturally (oh gosh will this table markdown syntax work in trac...)
| Scenario | With priority only | With priority + fallback |
| Multiple providers connected, all working | Preferred provider used | Preferred provider used |
| Preferred provider hits rate limit | Hard error | Next provider tried automatically |
| Preferred provider has an outage | Hard error | Next provider tried automatically |
| No providers connected | Error (unchanged) | Error (unchanged) |
The priority filter determines the order; the fallback loop determines what happens when an item in that order fails. Neither requires the other, but together they deliver the reliability that the existence of a multi-provider UI implies.
## Current workarounds and their limitations
| Approach | What it covers | What it misses |
| wpai_preferred_text/image/vision_models filters (bundled ai plugin) | Abstract_Ability subclasses | Direct wp_ai_client_prompt() callers; requires ai plugin |
| wp_get_preferred_ai_connector() (connector-priority plugin) | Anything that calls it explicitly | Must be called by every third-party developer; no fallback |
| script_module_data_* filter reordering | Connectors screen UI order | Runtime provider selection |
| No fallback mechanism exists at any layer | — | All callers |
A proof-of-concept plugin ([connector-priority](https://github.com/georgestephanis/connector-priority))
demonstrates the full UI and storage side: drag-and-drop ordering, REST-exposed
option, PHP API, and the script_module_data_* reordering. The remaining gap is
entirely within php-ai-client and requires the core changes described above.
## Prior art
- The bundled
aiplugin already implements this pattern one level belowPromptBuilder, viawpai_preferred_text_modelsetc. The proposedwp_ai_provider_priorityfilter is the same idea lifted to the layer that all callers share. - Production AI infrastructure (AWS Bedrock fallback models, Azure OpenAI fallback deployments, LangChain's fallback chains) universally treats "try next provider on failure" as a first-class concern, not an application-level responsibility.
- The connector-priority plugin's
_connector_priority_sort_models()function (which re-sorts[provider, model]pairs) is essentially the same algorithm as the proposedProviderRegistrychange, just applied at a different layer.
Change History (4)
This ticket was mentioned in Slack in #core-ai by georgestephanis. View the logs.
7 weeks ago
#4
@
3 weeks ago
@jason_the_adams, how do you see fit here? It isn't milestoned for WordPress 7.1, nor was it covered in https://make.wordpress.org/ai/2026/06/19/whats-coming-to-the-ai-client-in-wp-7-1/, so I'd like to get clarifications to triage it properly.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
As core changes to remediate would likely be in the php-ai-client package, I opened a PR there as a starting point:
https://github.com/WordPress/php-ai-client/pull/239