Skip to content

Commit 23f1af0

Browse files
committed
fix: handles support methods in an error state
1 parent 1c07c3e commit 23f1af0

2 files changed

Lines changed: 58 additions & 39 deletions

File tree

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

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@
3232
* handling instead of exceptions, snake_case method naming, and integration
3333
* with the Abilities API.
3434
*
35-
* Only the terminate methods will return a WP_Error, to not break the fluent
35+
* Only the generating methods will return a WP_Error, to not break the fluent
3636
* interface. As soon as any exception is caught in a chain of method calls,
3737
* the returned instance will be in an error state, and all subsequent method
3838
* calls will be no-ops that just return the same error state instance. Only
39-
* when a terminate method is called, the WP_Error will be returned.
39+
* when a generating method is called, the WP_Error will be returned.
4040
*
4141
* @since 6.8.0
4242
*
@@ -108,14 +108,14 @@ class WP_AI_Client_Prompt_Builder {
108108
private ?WP_Error $error = null;
109109

110110
/**
111-
* List of methods that terminate the fluent interface and return a result.
111+
* List of methods that generate a result from the prompt.
112112
*
113113
* Structured as a map for faster lookups.
114114
*
115115
* @since 6.8.0
116116
* @var array<string, bool>
117117
*/
118-
private static array $terminate_methods = array(
118+
private static array $generating_methods = array(
119119
'generate_result' => true,
120120
'generate_text_result' => true,
121121
'generate_image_result' => true,
@@ -131,6 +131,25 @@ class WP_AI_Client_Prompt_Builder {
131131
'generate_speeches' => true,
132132
);
133133

134+
/**
135+
* List of methods that check whether the prompt is supported.
136+
*
137+
* Structured as a map for faster lookups.
138+
*
139+
* @since 6.8.0
140+
* @var array<string, bool>
141+
*/
142+
private static array $support_check_methods = array(
143+
'is_supported' => true,
144+
'is_supported_for_text_generation' => true,
145+
'is_supported_for_image_generation' => true,
146+
'is_supported_for_text_to_speech_conversion' => true,
147+
'is_supported_for_video_generation' => true,
148+
'is_supported_for_speech_generation' => true,
149+
'is_supported_for_music_generation' => true,
150+
'is_supported_for_embedding_generation' => true,
151+
);
152+
134153
/**
135154
* Constructor.
136155
*
@@ -219,14 +238,17 @@ public function __call( string $name, array $arguments ) {
219238
* or return the same instance for other methods to maintain the fluent interface.
220239
*/
221240
if ( null !== $this->error ) {
222-
if ( self::is_terminating_method( $name ) ) {
241+
if ( self::is_generating_method( $name ) ) {
223242
return $this->error;
224243
}
244+
if ( self::is_support_check_method( $name ) ) {
245+
return false;
246+
}
225247
return $this;
226248
}
227249

228250
// Check if the prompt should be prevented for is_supported* and generate_*/convert_text_to_speech* methods.
229-
if ( $this->is_support_check_method( $name ) || $this->is_generating_method( $name ) ) {
251+
if ( self::is_support_check_method( $name ) || self::is_generating_method( $name ) ) {
230252
/**
231253
* Filters whether to prevent the prompt from being executed.
232254
*
@@ -239,7 +261,7 @@ public function __call( string $name, array $arguments ) {
239261

240262
if ( $prevent ) {
241263
// For is_supported* methods, return false.
242-
if ( $this->is_support_check_method( $name ) ) {
264+
if ( self::is_support_check_method( $name ) ) {
243265
return false;
244266
}
245267

@@ -252,7 +274,7 @@ public function __call( string $name, array $arguments ) {
252274
)
253275
);
254276

255-
if ( self::is_terminating_method( $name ) ) {
277+
if ( self::is_generating_method( $name ) ) {
256278
return $this->error;
257279
}
258280
return $this;
@@ -278,7 +300,7 @@ public function __call( string $name, array $arguments ) {
278300
)
279301
);
280302

281-
if ( self::is_terminating_method( $name ) ) {
303+
if ( self::is_generating_method( $name ) ) {
282304
return $this->error;
283305
}
284306
return $this;
@@ -293,8 +315,8 @@ public function __call( string $name, array $arguments ) {
293315
* @param string $name The method name.
294316
* @return bool True if the method is a support check method, false otherwise.
295317
*/
296-
protected function is_support_check_method( string $name ): bool {
297-
return str_starts_with( $name, 'is_supported' );
318+
private static function is_support_check_method( string $name ): bool {
319+
return isset( self::$support_check_methods[ $name ] );
298320
}
299321

300322
/**
@@ -305,21 +327,8 @@ protected function is_support_check_method( string $name ): bool {
305327
* @param string $name The method name.
306328
* @return bool True if the method is a generating method, false otherwise.
307329
*/
308-
protected function is_generating_method( string $name ): bool {
309-
return str_starts_with( $name, 'generate_' )
310-
|| str_starts_with( $name, 'convert_text_to_speech' );
311-
}
312-
313-
/**
314-
* Checks if a method is a terminating method.
315-
*
316-
* @since 6.8.0
317-
*
318-
* @param string $name The method name.
319-
* @return bool True if the method is a terminating method, false otherwise.
320-
*/
321-
private static function is_terminating_method( string $name ): bool {
322-
return isset( self::$terminate_methods[ $name ] );
330+
private static function is_generating_method( string $name ): bool {
331+
return isset( self::$generating_methods[ $name ] );
323332
}
324333

325334
/**

tests/phpunit/tests/ai-client/wpAiClientPromptBuilder.php

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,11 +2324,8 @@ public function test_error_state_fluent_calls_return_same_instance() {
23242324
$registry = AiClient::defaultRegistry();
23252325
$prompt_builder = new WP_AI_Client_Prompt_Builder( $registry );
23262326

2327-
// Simulate an error state by directly setting the error property.
2328-
$reflection_class = new ReflectionClass( WP_AI_Client_Prompt_Builder::class );
2329-
$error_property = $reflection_class->getProperty( 'error' );
2330-
$error_property->setAccessible( true );
2331-
$error_property->setValue( $prompt_builder, new WP_Error( 'test_error', 'Test error message' ) );
2327+
// Trigger an error state by calling a nonexistent method.
2328+
$prompt_builder->nonexistent_method();
23322329

23332330
$result = $prompt_builder->with_text( 'Test' );
23342331
$this->assertSame( $prompt_builder, $result, 'Fluent method should return same instance when in error state' );
@@ -2338,23 +2335,36 @@ public function test_error_state_fluent_calls_return_same_instance() {
23382335
}
23392336

23402337
/**
2341-
* Tests that terminating methods return WP_Error when in error state.
2338+
* Tests that support check methods return false when in error state.
23422339
*
23432340
* @ticket TBD
23442341
*/
2345-
public function test_terminating_methods_return_wp_error_in_error_state() {
2342+
public function test_support_check_methods_return_false_in_error_state() {
23462343
$registry = AiClient::defaultRegistry();
23472344
$prompt_builder = new WP_AI_Client_Prompt_Builder( $registry );
23482345

2349-
$test_error = new WP_Error( 'test_error', 'Test error message' );
2350-
$reflection_class = new ReflectionClass( WP_AI_Client_Prompt_Builder::class );
2351-
$error_property = $reflection_class->getProperty( 'error' );
2352-
$error_property->setAccessible( true );
2353-
$error_property->setValue( $prompt_builder, $test_error );
2346+
// Trigger an error state by calling a nonexistent method.
2347+
$prompt_builder->nonexistent_method();
2348+
2349+
$this->assertFalse( $prompt_builder->is_supported(), 'is_supported should return false when in error state' );
2350+
$this->assertFalse( $prompt_builder->is_supported_for_text_generation(), 'is_supported_for_text_generation should return false when in error state' );
2351+
}
2352+
2353+
/**
2354+
* Tests that generating methods return WP_Error when in error state.
2355+
*
2356+
* @ticket TBD
2357+
*/
2358+
public function test_generating_methods_return_wp_error_in_error_state() {
2359+
$registry = AiClient::defaultRegistry();
2360+
$prompt_builder = new WP_AI_Client_Prompt_Builder( $registry );
2361+
2362+
// Trigger an error state by calling a nonexistent method.
2363+
$prompt_builder->nonexistent_method();
23542364

23552365
$result = $prompt_builder->generate_text();
23562366
$this->assertWPError( $result, 'generate_text should return WP_Error when in error state' );
2357-
$this->assertSame( $test_error, $result, 'Should return the same WP_Error instance' );
2367+
$this->assertSame( 'prompt_builder_error', $result->get_error_code() );
23582368
}
23592369

23602370
/**

0 commit comments

Comments
 (0)