Make WordPress Core

Opened 13 days ago

Last modified 2 days ago

#64591 assigned feature request

Add WP AI Client

Reported by: flixos90's profile flixos90 Owned by: jason_the_adams's profile jason_the_adams
Milestone: 7.0 Priority: normal
Severity: normal Version:
Component: AI Keywords: has-patch has-unit-tests
Focuses: Cc:

Description (last modified by flixos90)

This ticket is for merging the WP AI Client into Core.

Technically, this means bundling the PHP AI Client as an external dependency in Core (similar to e.g. the Requests library), while the WP AI Client will become a direct part of Core. The package for the latter will most likely be discontinued after the merge.

See the merge proposal for additional context.

Change History (23)

#1 @flixos90
13 days ago

  • Description modified (diff)

This ticket was mentioned in Slack in #hosting by chaion07. View the logs.


13 days ago

#3 @schmitzoide
12 days ago

First off, this is a fantastic proposal. Having a provider-agnostic AI foundation in Core is exactly what the ecosystem needs, it will reduce fragmentation and give plugin developers a stable base to build on. Really excited to see this moving forward.

That said, I wanted to raise one potential design consideration regarding how WP AI Client might interact with the Abilities API.

The Question

If WP AI Client registers abilities like ai/prompt or ai/completion, could this create some philosophical tension?

  1. Layer confusion - Abilities typically represent "what WordPress can do". An ability to "call an AI model" feels more like external infrastructure that WordPress uses.
  1. Meta-recursion - The API was designed for AI to orchestrate WordPress. Having "invoke AI" as a discoverable ability could create circular confusion — a bit like listing "call the chef" as a menu item.
  1. Schema considerations - Abilities have deterministic schemas. AI responses are non-deterministic.
  1. Discovery implications - Plugins that auto-discover abilities might inadvertently expose "call external LLM" as a tool, confusing UX.

Possible Solutions

  • Option A: is_infrastructure metadata flag for filtering
  • Option B: Namespace convention (ai/* for internal use)
  • Option C: Keep WP AI Client as developer infrastructure without Abilities exposure

Again, great work on this proposal. Just wanted to flag this early in case it's helpful for the design. Happy to discuss further!

Last edited 12 days ago by schmitzoide (previous) (diff)

This ticket was mentioned in Slack in #core by audrasjb. View the logs.


12 days ago

This ticket was mentioned in Slack in #hosting by amykamala. View the logs.


12 days ago

This ticket was mentioned in PR #10881 on WordPress/wordpress-develop by @jason_the_adams.


10 days ago
#6

  • Keywords has-patch added; needs-patch removed

Trac ticket: https://core.trac.wordpress.org/ticket/64591
Merge Proposal: https://make.wordpress.org/core/2026/02/03/proposal-for-merging-wp-ai-client-into-wordpress-7-0

## Summary

Adds a provider-agnostic AI Client, enabling developers to interact with generative AI services through a single, fluent API — without needing to know which provider is configured.

This PR includes three layers:

  • PHP AI Client SDK (php-ai-client): The upstream SDK from WordPress/php-ai-client, bundled into wp-includes/php-ai-client/ with all third-party dependencies (PSR interfaces, HTTPlug) scoped to WordPress\AiClientDependencies\* to avoid conflicts with plugins shipping their own versions.
  • Import tooling (tools/php-ai-client/): An installer script and PHP-Scoper configuration that fetches, scopes, and reorganizes the SDK for bundling. Running bash tools/php-ai-client/installer.sh reproduces the bundled output deterministically.
  • WP AI Client (ai-client-utils/, ai-client.php): The WordPress integration layer. This provides minimal PSR-7/PSR-17 implementations backed by string buffers and wp_parse_url(), an HTTP client adapter that routes requests through wp_remote_request(), a discovery strategy so the SDK automatically finds these implementations, and an event dispatcher that bridges PSR-14 events to WordPress hooks.

The public API is a single function:

$summary = wp_ai_client_prompt( 'Summarize this post' )
    ->with_text( $post->post_content )
    ->generate_text();

WP_AI_Client_Prompt_Builder wraps the SDK's fluent builder with WordPress conventions — snake_case methods, WP_Error returns instead of exceptions, and using_abilities() for connecting the Abilities API to AI function calling.

The wp_ai_client_prevent_prompt filter gives site owners and plugins centralized control over AI availability. When a prompt is prevented, generating methods return WP_Error while is_supported_* methods return false — giving plugin developers a graceful way to hide AI features entirely when AI is not available.

This gives plugin and theme developers a stable, provider-neutral way to add AI features without bundling their own HTTP clients or managing provider-specific SDKs.

## Follow up PRs

There will be a couple more PRs. I broke up the WP AI Client, introducing only the main core files in this one. Following PRs will be:

  • The REST API
  • The provider credentials settings screen

## Use of AI Tools

This is a compilation of work from the PHP AI Client and WP AI Client repositories, with some changes made in porting to core. Claude Code was used in both the original development of those packages as well as the porting over and creation of the tooling. All code was generated by Claude Code and reviewed by myself and @felixarntz.

@johnbillion commented on PR #10881:


5 days ago
#7

Might any of these 3p libraries potentially be used outside of the AI client in the future? ie. they might benefit from being in the higher level WordPress namespace rather than WordPress\AiClient.

Extenders might refer to that 3p code as soon as it's in, so we can't change the namespace at a later date.

@swissspidy commented on PR #10881:


5 days ago
#8

FYI there are 50+ Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 deprecation notices introduced by this PR.

@jason_the_adams commented on PR #10881:


5 days ago
#9

I was fixing that as you posted the comment, @swissspidy. 😄

@jason_the_adams commented on PR #10881:


5 days ago
#10

Might any of these 3p libraries potentially be used outside of the AI client in the future? ie. they might benefit from being in the higher level WordPress namespace rather than WordPress\AiClient.

Extenders might refer to that 3p code as soon as it's in, so we can't change the namespace at a later date.

I'm certainly open to this! What libraries are you thinking of, specifically?

@jason_the_adams commented on PR #10881:


5 days ago
#11

Thanks for looking over this, @dkotter! I've resolved most of what you raised. I'm temporarily shifting to get the settings screen PR in place so we can start testing!

This ticket was mentioned in PR #10904 on WordPress/wordpress-develop by @jason_the_adams.


5 days ago
#12

Trac ticket: https://core.trac.wordpress.org/ticket/64591
Merge Proposal: https://make.wordpress.org/core/2026/02/03/proposal-for-merging-wp-ai-client-into-wordpress-7-0

This is a part of #10881. I meant for this to stack on that so the changes in this are clear, but unfortunately I can't stack because both branches are in my forked repo.

## Summary

Adds an AI Services settings screen under Settings > AI Services where site administrators can enter API credentials for AI providers. Without this, wp_ai_client_prompt() has no way to authenticate with any provider.

  • WP_AI_Client_Credentials_Manager collects provider metadata from the SDK, registers the credentials option with sanitization, and passes stored API keys to the SDK on each request
  • The settings page renders a password field for each registered cloud provider, with links to the provider's API key management page
  • Provider collection and credential passing happen after init so plugins that register providers are picked up
  • Includes PHPUnit tests for the credentials manager

Ported from the API_Credentials_Manager and API_Credentials_Settings_Screen in the wp-ai-client plugin, adapted to core conventions (no namespaces, _doing_it_wrong() instead of exceptions, no text domain, etc.).

https://github.com/user-attachments/assets/fdc6c4c1-f64d-4704-a41b-ca9bdf74ae35

## Open question

The Settings > AI Services menu item is currently hidden when no cloud providers are registered (since the page would be empty). Is this the right behavior, or should the page always be visible with a message like "No AI providers are currently available"? Hiding it is cleaner but could be confusing if someone is looking for the page before installing a provider plugin.

## Test plan

  • [ ] Install a provider plugin (e.g. Google AI provider), navigate to Settings > AI Services, verify fields appear
  • [ ] Enter an API key, save, reload — verify value persists
  • [ ] Verify wp_ai_client_prompt() can authenticate using the stored key
  • [ ] Deactivate all provider plugins — verify menu item disappears
  • [ ] npm run test:php -- --group ai-client

Trac ticket:

## Use of AI Tools

@desrosj commented on PR #10881:


5 days ago
#13

So I updated the test coverage workflow to run every time this PR is updated (please revert this before a final commit to SVN. In the status checks, you'll find two codecov lines.

Surprisingly, it seems that 96%+ of this PR is actually covered by tests (which excludes the bundled library parts of this PR based on the PHPUnit configuration file changes), and this PR actually _increases_ overall test coverages by roughly 2-tenths of a percent.

Chatting it through with @aaronjorbin, @jeffpaul, and @felixarntz just now, this _seems_ to make sense. The wp-ai-client is essentially a pass through, so it's not difficult to have "coverage". But it's unlikely that a high percentage of the underlying PHP SDK is being tested through the wp-ai-client tests here.

I do feel a bit better about the test coverage part of this. I think this will need to be a blended approach. There should be a high level of coverage for the non-bundled library code here combined with the test coverage within the PHP SDK library. @aaronjorbin has created an issue to follow up with adding test coverage reporting to the php-ai-client repository to track and confirm this.

@jason_the_adams commented on PR #10904:


5 days ago
#14

Given how merging works in WordPress (a single SVN commit) I'm switching this to a draft PR. It's useful for testing!

This ticket was mentioned in Slack in #core-test by juanmaguitar. View the logs.


4 days ago

@dkotter commented on PR #10904:


4 days ago
#17

The Settings > AI Services menu item is currently hidden when no cloud providers are registered (since the page would be empty). Is this the right behavior, or should the page always be visible with a message like "No AI providers are currently available"? Hiding it is cleaner but could be confusing if someone is looking for the page before installing a provider plugin.

I know there's been discussion around discoverability in regards to the individual AI providers. Could make a case that instead of hiding the page when no providers are registered we instead update the page to provide instructions on how to find and install a provider?

@peterwilsoncc commented on PR #10881:


4 days ago
#18

@JasonTheAdams Are you able to add some testing notes to the PR description. I'm having trouble finguring out what needs to be done to add providers to the settings screen with the AI Experiments plugin installed. The menu page is available but without any form fields.

https://github.com/user-attachments/assets/aca5ab82-a353-4674-9a43-5b7f1e0d1020

This ticket was mentioned in PR #10915 on WordPress/wordpress-develop by @jason_the_adams.


4 days ago
#19

Trac ticket: https://core.trac.wordpress.org/ticket/64591
Merge Proposal: https://make.wordpress.org/core/2026/02/03/proposal-for-merging-wp-ai-client-into-wordpress-7-0

This is a part of https://github.com/WordPress/wordpress-develop/pull/10881. I meant for this to stack on that so the changes in this are clear, but unfortunately I can't stack because both branches are in my forked repo.

## Summary

Ports the REST API, JavaScript client, and capabilities system from the WP AI Client plugin into WordPress Core.

This gives WordPress a complete client-side AI API that mirrors the server-side wp_ai_client_prompt() API already in Core, along with REST endpoints that the JavaScript layer (and any external consumer) can use.

### What's being ported

REST API (wp-ai/v1)

  • POST /wp-ai/v1/generate — Sends a prompt to an AI model and returns a GenerativeAiResult. Accepts messages, model config, provider/model selection, model preferences, and request options.
  • POST /wp-ai/v1/is-supported — Checks whether the current prompt configuration is supported by any available model, without actually running the generation.
  • GET /wp-ai/v1/providers — Lists all registered AI providers.
  • GET /wp-ai/v1/providers/{id} — Retrieves a single provider's metadata.
  • GET /wp-ai/v1/providers/{id}/models — Lists models available from a specific provider (requires the provider to be configured with credentials).
  • GET /wp-ai/v1/providers/{id}/models/{modelId} — Retrieves a single model's metadata.

The generate/is-supported endpoints wrap wp_ai_client_prompt() — the same public API that server-side PHP consumers use — so behavior is consistent between PHP and JS.

JavaScript Client (wp-ai-client)

A wp.aiClient global (registered as the wp-ai-client script handle) that provides:

  • wp.aiClient.prompt() — A fluent PromptBuilder class mirroring the PHP API: .withText(), .usingModel(), .usingTemperature(), .generateText(), .generateImage(), .isSupported(), etc. All generation methods return Promises that call the REST endpoints.
  • Provider/model data store — A @wordpress/data store (wp-ai-client/providers-models) with selectors/resolvers for getProviders(), getProvider(), getProviderModels(), getProviderModel(). Data is fetched lazily via the REST API and cached in the store.
  • Enums — JS constants for Capability, MessageRole, FileType, FinishReason, Modality, ProviderType, etc., matching the PHP SDK enums.
  • GenerativeAiResult wrapper with convenience extraction methods (toText(), toTexts(), toFile(), toImageFile(), toAudioFile(), etc.).

Capabilities

Three new meta-capabilities gate access to the REST endpoints:

Capability Gates Default
prompt_ai generate, is-supported Granted to users with manage_options
list_ai_providers providers (list & single) Granted to users with manage_options
list_ai_models providers/{id}/models routes Granted to users with manage_options

These are implemented as user_has_cap filter callbacks (same pattern as install_languages, resume_plugins, etc.) so they can be removed and replaced by plugins or site-specific code.

JSON Schema Converter

A small utility (WP_AI_Client_JSON_Schema_Converter) that converts standard JSON Schema required arrays into the per-property required: true booleans that WordPress REST API validation expects. Used to bridge the SDK's getJsonSchema() output into valid WP REST args.

### Open question: capabilities direction

The current approach follows the upstream plugin exactly — three separate meta-capabilities dynamically granted via user_has_cap filters to anyone with manage_options. This is simple and removable, but worth discussing:

  • Should prompt_ai default to all administrators, or be more restrictive? AI generation can have cost implications (API credits), and the current gate (manage_options) means any admin on a multisite network could generate content. Tying it to a more specific primitive capability or making it opt-in might be more appropriate for Core.
  • Are list_ai_providers and list_ai_models worth separating from prompt_ai? In practice, anyone who can prompt also needs to know what's available. Merging them into a single capability (or making listing public to all authenticated users) would simplify the permission model.
  • Should these use map_meta_cap instead of user_has_cap? The user_has_cap filter pattern works but is less discoverable than a map_meta_cap mapping. The Abilities API uses primitive capabilities stored in roles, which is the more conventional Core pattern.

## Test plan

  • [ ] npm run test:php -- --group ai-client — all 326 tests pass
  • [ ] composer lint:errors on new PHP files — 0 errors
  • [ ] npm run build:devai-client.js and ai-client.min.js generated
  • [ ] Verify REST endpoint discovery: GET /wp-json/wp-ai/v1 returns route listing
  • [ ] Verify capability gating: subscriber gets rest_forbidden, admin gets through
  • [ ] Verify wp-ai-client script is registered with wp-api-fetch and wp-data as dependencies

Use of AI Tools
This is a compilation of work from the PHP AI Client and WP AI Client repositories, with some changes made in porting to core. Claude Code was used in both the original development of those packages as well as the porting over and creation of the tooling. All code was generated by Claude Code and reviewed by myself and @felixarntz.

@jason_the_adams commented on PR #10915:


4 days ago
#20

As a note, I wouldn't consider this something critical to get into core. If we don't want this on 7.0 it shouldn't hold up #10881. I'm porting this over for consideration since it does exist in the WP AI Client.

@jason_the_adams commented on PR #10881:


4 days ago
#21

@peterwilsoncc Done!

#22 @flixos90
2 days ago

  • Owner set to jason_the_adams
  • Status changed from new to assigned

#23 @flixos90
2 days ago

  • Keywords has-unit-tests added; needs-unit-tests removed
Note: See TracTickets for help on using tickets.