Skip to content

Commit e7c5f54

Browse files
AI: Introduce wp_supports_ai() function to control LLM-related features.
This includes a `WP_AI_SUPPORT` constant and a `wp_supports_ai` filter. When false, - `_wp_connectors_get_provider_settings()` will return an empty array (short-circuiting the other functionality). - `WP_AI_Client_Prompt_Builder()` will short-circuit the construction with a `WP_Error()`. `wp_ai_client_prompt()` will still return an instance, to allow for fluidity to remain intact. Priority: `WP_AI_SUPPORT` > `add_filter( 'wp_supports_ai', ...) > (default: true)` Follow-up to [61943], [61749], [61943]. Props justlevine, westonruter, gziolo, flixos90, romainmrhenry, ahortin, chrismcelroyseo, SergeyBiryukov. See #64706. git-svn-id: https://develop.svn.wordpress.org/trunk@62067 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 4f26f0e commit e7c5f54

7 files changed

Lines changed: 168 additions & 216 deletions

File tree

src/wp-includes/ai-client.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,30 @@
99

1010
use WordPress\AiClient\AiClient;
1111

12+
/**
13+
* Returns whether AI features are supported in the current environment.
14+
*
15+
* @since 7.0.0
16+
*
17+
* @return bool Whether AI features are supported.
18+
*/
19+
function wp_supports_ai(): bool {
20+
$is_enabled = defined( 'WP_AI_SUPPORT' ) ? WP_AI_SUPPORT : true;
21+
22+
/**
23+
* Filters whether the current request should use AI.
24+
*
25+
* This allows plugins and 3rd-party code to disable AI features on a per-request basis, or to even override explicit
26+
* preferences defined by the site owner.
27+
*
28+
* @since 7.0.0
29+
*
30+
* @param bool $is_enabled Whether the current request should use AI. Default to WP_AI_SUPPORT constant, or true if
31+
* the constant is not defined.
32+
*/
33+
return (bool) apply_filters( 'wp_supports_ai', $is_enabled );
34+
}
35+
1236
/**
1337
* Creates a new AI prompt builder using the default provider registry.
1438
*

src/wp-includes/ai-client/class-wp-ai-client-prompt-builder.php

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
*
4747
* @since 7.0.0
4848
*
49+
* @phpstan-import-type Prompt from PromptBuilder
50+
*
4951
* @method self with_text(string $text) Adds text to the current message.
5052
* @method self with_file($file, ?string $mimeType = null) Adds a file to the current message.
5153
* @method self with_function_response(FunctionResponse $functionResponse) Adds a function response to the current message.
@@ -170,14 +172,14 @@ class WP_AI_Client_Prompt_Builder {
170172
*
171173
* @since 7.0.0
172174
*
173-
* @param ProviderRegistry $registry The provider registry for finding suitable models.
174-
* @param string|MessagePart|Message|array|list<string|MessagePart|array>|list<Message>|null $prompt Optional. Initial prompt content.
175-
* A string for simple text prompts,
176-
* a MessagePart or Message object for
177-
* structured content, an array for a
178-
* message array shape, or a list of
179-
* parts or messages for multi-turn
180-
* conversations. Default null.
175+
* @param ProviderRegistry $registry The provider registry for finding suitable models.
176+
* @param Prompt $prompt Optional. Initial prompt content.
177+
* A string for simple text prompts,
178+
* a MessagePart or Message object for
179+
* structured content, an array for a
180+
* message array shape, or a list of
181+
* parts or messages for multi-turn
182+
* conversations. Default null.
181183
*/
182184
public function __construct( ProviderRegistry $registry, $prompt = null ) {
183185
try {
@@ -289,26 +291,35 @@ public function __call( string $name, array $arguments ) {
289291

290292
// Check if the prompt should be prevented for is_supported* and generate_*/convert_text_to_speech* methods.
291293
if ( self::is_support_check_method( $name ) || self::is_generating_method( $name ) ) {
292-
/**
293-
* Filters whether to prevent the prompt from being executed.
294-
*
295-
* @since 7.0.0
296-
*
297-
* @param bool $prevent Whether to prevent the prompt. Default false.
298-
* @param WP_AI_Client_Prompt_Builder $builder A clone of the prompt builder instance (read-only).
299-
*/
300-
$prevent = (bool) apply_filters( 'wp_ai_client_prevent_prompt', false, clone $this );
294+
// If AI is not supported, then there's no need to apply the filter as the prompt will be prevented anyway.
295+
$is_ai_disabled = ! wp_supports_ai();
296+
$prevent = $is_ai_disabled;
297+
if ( ! $prevent ) {
298+
/**
299+
* Filters whether to prevent the prompt from being executed.
300+
*
301+
* @since 7.0.0
302+
*
303+
* @param bool $prevent Whether to prevent the prompt. Default false.
304+
* @param WP_AI_Client_Prompt_Builder $builder A clone of the prompt builder instance (read-only).
305+
*/
306+
$prevent = (bool) apply_filters( 'wp_ai_client_prevent_prompt', false, clone $this );
307+
}
301308

302309
if ( $prevent ) {
303310
// For is_supported* methods, return false.
304311
if ( self::is_support_check_method( $name ) ) {
305312
return false;
306313
}
307314

315+
$error_message = $is_ai_disabled
316+
? __( 'AI features are not supported in this environment.' )
317+
: __( 'Prompt execution was prevented by a filter.' );
318+
308319
// For generate_* and convert_text_to_speech* methods, create a WP_Error.
309320
$this->error = new WP_Error(
310321
'prompt_prevented',
311-
__( 'Prompt execution was prevented by a filter.' ),
322+
$error_message,
312323
array(
313324
'status' => 503,
314325
)
@@ -423,7 +434,8 @@ private static function is_generating_method( string $name ): bool {
423434
protected function get_builder_callable( string $name ): callable {
424435
$camel_case_name = $this->snake_to_camel_case( $name );
425436

426-
if ( ! is_callable( array( $this->builder, $camel_case_name ) ) ) {
437+
$method = array( $this->builder, $camel_case_name );
438+
if ( ! is_callable( $method ) ) {
427439
throw new BadMethodCallException(
428440
sprintf(
429441
/* translators: 1: Method name. 2: Class name. */
@@ -434,7 +446,7 @@ protected function get_builder_callable( string $name ): callable {
434446
);
435447
}
436448

437-
return array( $this->builder, $camel_case_name );
449+
return $method;
438450
}
439451

440452
/**

src/wp-includes/class-wp-connector-registry.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ public function register( string $id, array $args ): ?array {
170170
return null;
171171
}
172172

173+
if ( 'ai_provider' === $args['type'] && ! wp_supports_ai() ) {
174+
// No need for a `doing_it_wrong` as AI support is disabled intentionally.
175+
return null;
176+
}
177+
173178
$connector = array(
174179
'name' => $args['name'],
175180
'description' => isset( $args['description'] ) && is_string( $args['description'] ) ? $args['description'] : '',

0 commit comments

Comments
 (0)