88 */
99
1010use WordPress \AiClient \Builders \PromptBuilder ;
11+ use WordPress \AiClient \Common \Exception \InvalidArgumentException ;
12+ use WordPress \AiClient \Common \Exception \TokenLimitReachedException ;
1113use WordPress \AiClient \Files \DTO \File ;
1214use WordPress \AiClient \Files \Enums \FileTypeEnum ;
1315use WordPress \AiClient \Files \Enums \MediaOrientationEnum ;
1416use WordPress \AiClient \Messages \DTO \Message ;
1517use WordPress \AiClient \Messages \DTO \MessagePart ;
1618use WordPress \AiClient \Messages \Enums \ModalityEnum ;
1719use WordPress \AiClient \Providers \Http \DTO \RequestOptions ;
20+ use WordPress \AiClient \Providers \Http \Exception \ClientException ;
21+ use WordPress \AiClient \Providers \Http \Exception \NetworkException ;
22+ use WordPress \AiClient \Providers \Http \Exception \ServerException ;
1823use WordPress \AiClient \Providers \Models \Contracts \ModelInterface ;
1924use WordPress \AiClient \Providers \Models \DTO \ModelConfig ;
2025use WordPress \AiClient \Providers \Models \Enums \CapabilityEnum ;
@@ -179,13 +184,7 @@ public function __construct( ProviderRegistry $registry, $prompt = null ) {
179184 $ this ->builder = new PromptBuilder ( $ registry , $ prompt );
180185 } catch ( Exception $ e ) {
181186 $ this ->builder = new PromptBuilder ( $ registry );
182- $ this ->error = new WP_Error (
183- 'prompt_builder_error ' ,
184- $ e ->getMessage (),
185- array (
186- 'exception_class ' => get_class ( $ e ),
187- )
188- );
187+ $ this ->error = $ this ->exception_to_wp_error ( $ e );
189188 }
190189
191190 /**
@@ -311,7 +310,7 @@ public function __call( string $name, array $arguments ) {
311310 'prompt_prevented ' ,
312311 __ ( 'Prompt execution was prevented by a filter. ' ),
313312 array (
314- 'exception_class ' => ' WP_AI_Client_Prompt_Prevented ' ,
313+ 'status ' => 503 ,
315314 )
316315 );
317316
@@ -333,13 +332,7 @@ public function __call( string $name, array $arguments ) {
333332
334333 return $ result ;
335334 } catch ( Exception $ e ) {
336- $ this ->error = new WP_Error (
337- 'prompt_builder_error ' ,
338- $ e ->getMessage (),
339- array (
340- 'exception_class ' => get_class ( $ e ),
341- )
342- );
335+ $ this ->error = $ this ->exception_to_wp_error ( $ e );
343336
344337 if ( self ::is_generating_method ( $ name ) ) {
345338 return $ this ->error ;
@@ -348,6 +341,51 @@ public function __call( string $name, array $arguments ) {
348341 }
349342 }
350343
344+ /**
345+ * Converts an exception into a WP_Error with a structured error code and message.
346+ *
347+ * This method maps different exception types to specific WP_Error codes and HTTP status codes.
348+ * The presence of the status codes means these WP_Error objects can be easily used in REST API responses
349+ * or other contexts where HTTP semantics are relevant.
350+ *
351+ * @since 7.0.0
352+ *
353+ * @param Exception $e The exception to convert.
354+ * @return WP_Error The resulting WP_Error object.
355+ */
356+ private function exception_to_wp_error ( Exception $ e ): WP_Error {
357+ if ( $ e instanceof NetworkException ) {
358+ $ error_code = 'prompt_network_error ' ;
359+ $ status_code = 503 ;
360+ } elseif ( $ e instanceof ClientException ) {
361+ // `ClientException` uses HTTP status codes as exception codes, so we can rely on them.
362+ $ error_code = 'prompt_client_error ' ;
363+ $ status_code = $ e ->getCode () ? $ e ->getCode () : 400 ;
364+ } elseif ( $ e instanceof ServerException ) {
365+ // `ServerException` uses HTTP status codes as exception codes, so we can rely on them.
366+ $ error_code = 'prompt_upstream_server_error ' ;
367+ $ status_code = $ e ->getCode () ? $ e ->getCode () : 500 ;
368+ } elseif ( $ e instanceof TokenLimitReachedException ) {
369+ $ error_code = 'prompt_token_limit_reached ' ;
370+ $ status_code = 400 ;
371+ } elseif ( $ e instanceof InvalidArgumentException ) {
372+ $ error_code = 'prompt_invalid_argument ' ;
373+ $ status_code = 400 ;
374+ } else {
375+ $ error_code = 'prompt_builder_error ' ;
376+ $ status_code = 500 ;
377+ }
378+
379+ return new WP_Error (
380+ $ error_code ,
381+ $ e ->getMessage (),
382+ array (
383+ 'status ' => $ status_code ,
384+ 'exception_class ' => get_class ( $ e ),
385+ )
386+ );
387+ }
388+
351389 /**
352390 * Checks if a method name is a support check method (is_supported*).
353391 *
0 commit comments