File manager - Edit - /home/gzbnyc5/avenuesny.com/wp-includes/js/imgareaselect/ai-client.tar
Back
adapters/class-wp-ai-client-cache.php 0000644 00000013662 15206745041 0013531 0 ustar 00 <?php /** * WP AI Client: WP_AI_Client_Cache class * * @package WordPress * @subpackage AI * @since 7.0.0 */ use WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface; /** * WordPress-specific PSR-16 cache adapter for the AI Client. * * Bridges PSR-16 cache operations to WordPress object cache functions, * enabling the AI client to leverage WordPress caching infrastructure. * * @since 7.0.0 * @internal Intended only to wire up the PHP AI Client SDK to WordPress's caching system. * @access private */ class WP_AI_Client_Cache implements CacheInterface { /** * Cache group used for all cache operations. * * @since 7.0.0 * @var string */ private const CACHE_GROUP = 'wp_ai_client'; /** * Fetches a value from the cache. * * @since 7.0.0 * * @param string $key The unique key of this item in the cache. * @param mixed $default_value Default value to return if the key does not exist. * @return mixed The value of the item from the cache, or $default_value in case of cache miss. */ public function get( $key, $default_value = null ) { $found = false; $value = wp_cache_get( $key, self::CACHE_GROUP, false, $found ); if ( ! $found ) { return $default_value; } return $value; } /** * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. * * @since 7.0.0 * * @param string $key The key of the item to store. * @param mixed $value The value of the item to store, must be serializable. * @param null|int|DateInterval $ttl Optional. The TTL value of this item. * @return bool True on success and false on failure. */ public function set( $key, $value, $ttl = null ): bool { $expire = $this->ttl_to_seconds( $ttl ); return wp_cache_set( $key, $value, self::CACHE_GROUP, $expire ); } /** * Delete an item from the cache by its unique key. * * @since 7.0.0 * * @param string $key The unique cache key of the item to delete. * @return bool True if the item was successfully removed. False if there was an error. */ public function delete( $key ): bool { return wp_cache_delete( $key, self::CACHE_GROUP ); } /** * Wipes clean the entire cache's keys. * * This method only clears the cache group used by this adapter. If the underlying * cache implementation does not support group flushing, this method returns false. * * @since 7.0.0 * * @return bool True on success and false on failure. */ public function clear(): bool { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { return false; } return wp_cache_flush_group( self::CACHE_GROUP ); } /** * Obtains multiple cache items by their unique keys. * * @since 7.0.0 * * @param iterable<string> $keys A list of keys that can be obtained in a single operation. * @param mixed $default_value Default value to return for keys that do not exist. * @return array<string, mixed> A list of key => value pairs. */ public function getMultiple( $keys, $default_value = null ): array { /** * Keys array. * * @var array<string> $keys_array */ $keys_array = $this->iterable_to_array( $keys ); $values = wp_cache_get_multiple( $keys_array, self::CACHE_GROUP ); $result = array(); foreach ( $keys_array as $key ) { if ( false === $values[ $key ] ) { // Could be a stored false or a cache miss — disambiguate via get(). $result[ $key ] = $this->get( $key, $default_value ); } else { $result[ $key ] = $values[ $key ]; } } return $result; } /** * Persists a set of key => value pairs in the cache, with an optional TTL. * * @since 7.0.0 * * @param iterable<string, mixed> $values A list of key => value pairs for a multiple-set operation. * @param null|int|DateInterval $ttl Optional. The TTL value of this item. * @return bool True on success and false on failure. */ public function setMultiple( $values, $ttl = null ): bool { $values_array = $this->iterable_to_array( $values ); $expire = $this->ttl_to_seconds( $ttl ); $results = wp_cache_set_multiple( $values_array, self::CACHE_GROUP, $expire ); // Return true only if all operations succeeded. return ! in_array( false, $results, true ); } /** * Deletes multiple cache items in a single operation. * * @since 7.0.0 * * @param iterable<string> $keys A list of string-based keys to be deleted. * @return bool True if the items were successfully removed. False if there was an error. */ public function deleteMultiple( $keys ): bool { $keys_array = $this->iterable_to_array( $keys ); $results = wp_cache_delete_multiple( $keys_array, self::CACHE_GROUP ); // Return true only if all operations succeeded. return ! in_array( false, $results, true ); } /** * Determines whether an item is present in the cache. * * @since 7.0.0 * * @param string $key The cache item key. * @return bool True if the item exists in the cache, false otherwise. */ public function has( $key ): bool { $found = false; wp_cache_get( $key, self::CACHE_GROUP, false, $found ); return (bool) $found; } /** * Converts a PSR-16 TTL value to seconds for WordPress cache functions. * * @since 7.0.0 * * @param null|int|DateInterval $ttl The TTL value. * @return int The TTL in seconds, or 0 for no expiration. */ private function ttl_to_seconds( $ttl ): int { if ( null === $ttl ) { return 0; } if ( $ttl instanceof DateInterval ) { $now = new DateTime(); $end = ( clone $now )->add( $ttl ); return $end->getTimestamp() - $now->getTimestamp(); } return max( 0, (int) $ttl ); } /** * Converts an iterable to an array. * * @since 7.0.0 * * @param iterable<mixed> $items The iterable to convert. * @return array<mixed> The array. */ private function iterable_to_array( $items ): array { if ( is_array( $items ) ) { return $items; } return iterator_to_array( $items ); } } adapters/class-wp-ai-client-event-dispatcher.php 0000644 00000004773 15206745041 0015736 0 ustar 00 <?php /** * WP AI Client: WP_AI_Client_Event_Dispatcher class * * @package WordPress * @subpackage AI * @since 7.0.0 */ use WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface; /** * WordPress-specific PSR-14 event dispatcher for the AI Client. * * Bridges PSR-14 events to WordPress action hooks, enabling plugins to hook * into AI client lifecycle events. * * @since 7.0.0 * @internal Intended only to wire up the PHP AI Client SDK to WordPress's hook system. * @access private */ class WP_AI_Client_Event_Dispatcher implements EventDispatcherInterface { /** * Dispatches an event to WordPress action hooks. * * Converts the event class name to a WordPress action hook name and fires it. * For example, BeforeGenerateResultEvent becomes wp_ai_client_before_generate_result. * * @since 7.0.0 * * @param object $event The event object to dispatch. * @return object The same event object, potentially modified by listeners. */ public function dispatch( object $event ): object { $event_name = $this->get_hook_name_portion_for_event( $event ); /** * Fires when an AI client event is dispatched. * * The dynamic portion of the hook name, `$event_name`, refers to the * snake_case version of the event class name, without the `_event` suffix. * * For example, an event class named `BeforeGenerateResultEvent` will fire the * `wp_ai_client_before_generate_result` action hook. * * In practice, the available action hook names are: * * - wp_ai_client_before_generate_result * - wp_ai_client_after_generate_result * * @since 7.0.0 * * @param object $event The event object. */ do_action( "wp_ai_client_{$event_name}", $event ); return $event; } /** * Converts an event object class name to a WordPress action hook name portion. * * @since 7.0.0 * * @param object $event The event object. * @return string The hook name portion derived from the event class name. */ private function get_hook_name_portion_for_event( object $event ): string { $class_name = get_class( $event ); $pos = strrpos( $class_name, '\\' ); $short_name = false !== $pos ? substr( $class_name, $pos + 1 ) : $class_name; // Convert PascalCase to snake_case. $snake_case = strtolower( (string) preg_replace( '/([a-z])([A-Z])/', '$1_$2', $short_name ) ); // Strip '_event' suffix if present. if ( str_ends_with( $snake_case, '_event' ) ) { $snake_case = (string) substr( $snake_case, 0, -6 ); } return $snake_case; } } adapters/class-wp-ai-client-http-client.php 0000644 00000015057 15206745041 0014721 0 ustar 00 <?php /** * WP AI Client: WP_AI_Client_HTTP_Client class * * @package WordPress * @subpackage AI * @since 7.0.0 */ use WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface; use WordPress\AiClientDependencies\Psr\Http\Message\RequestInterface; use WordPress\AiClientDependencies\Psr\Http\Message\ResponseInterface; use WordPress\AiClientDependencies\Psr\Http\Message\ResponseFactoryInterface; use WordPress\AiClientDependencies\Psr\Http\Message\StreamFactoryInterface; use WordPress\AiClient\Providers\Http\Contracts\ClientWithOptionsInterface; use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Http\Exception\NetworkException; /** * PSR-18 HTTP Client adapter using WordPress HTTP API. * * Allows WordPress HTTP functions to be used as a PSR-18 compliant HTTP client * for the AI Client SDK. * * @since 7.0.0 * @internal Intended only to wire up the PHP AI Client SDK to WordPress's HTTP client. * @access private */ class WP_AI_Client_HTTP_Client implements ClientInterface, ClientWithOptionsInterface { /** * Response factory instance. * * @since 7.0.0 */ private ResponseFactoryInterface $response_factory; /** * Stream factory instance. * * @since 7.0.0 */ private StreamFactoryInterface $stream_factory; /** * Constructor. * * @since 7.0.0 * * @param ResponseFactoryInterface $response_factory PSR-17 Response factory. * @param StreamFactoryInterface $stream_factory PSR-17 Stream factory. */ public function __construct( ResponseFactoryInterface $response_factory, StreamFactoryInterface $stream_factory ) { $this->response_factory = $response_factory; $this->stream_factory = $stream_factory; } /** * Sends a PSR-7 request and returns a PSR-7 response. * * @since 7.0.0 * * @param RequestInterface $request The PSR-7 request. * @return ResponseInterface The PSR-7 response. * * @throws NetworkException If the WordPress HTTP request fails. */ public function sendRequest( RequestInterface $request ): ResponseInterface { $args = $this->prepare_wp_args( $request ); $url = (string) $request->getUri(); $response = wp_safe_remote_request( $url, $args ); if ( is_wp_error( $response ) ) { $message = sprintf( /* translators: 1: HTTP method (e.g. GET, POST). 2: Request URL. 3: Error message. */ __( 'Network error occurred while sending %1$s request to %2$s: %3$s' ), $request->getMethod(), $url, $response->get_error_message() ); throw new NetworkException( $message ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped } return $this->create_psr_response( $response ); } /** * Sends a PSR-7 request with transport options and returns a PSR-7 response. * * @since 7.0.0 * * @param RequestInterface $request The PSR-7 request. * @param RequestOptions $options Transport options for the request. * @return ResponseInterface The PSR-7 response. * * @throws NetworkException If the WordPress HTTP request fails. */ public function sendRequestWithOptions( RequestInterface $request, RequestOptions $options ): ResponseInterface { $args = $this->prepare_wp_args( $request, $options ); $url = (string) $request->getUri(); $response = wp_safe_remote_request( $url, $args ); if ( is_wp_error( $response ) ) { $message = sprintf( /* translators: 1: Request URL. 2: Error message. */ __( 'Network error occurred while sending request to %1$s: %2$s' ), $url, $response->get_error_message() ); throw new NetworkException( $message, // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped $response->get_error_code() ? (int) $response->get_error_code() : 0 ); } return $this->create_psr_response( $response ); } /** * Prepares WordPress HTTP API arguments from a PSR-7 request. * * @since 7.0.0 * * @param RequestInterface $request The PSR-7 request. * @param RequestOptions|null $options Optional transport options for the request. * @return array<string, mixed> WordPress HTTP API arguments. */ private function prepare_wp_args( RequestInterface $request, ?RequestOptions $options = null ): array { $args = array( 'method' => $request->getMethod(), 'headers' => $this->prepare_headers( $request ), 'body' => $this->prepare_body( $request ), 'httpversion' => $request->getProtocolVersion(), 'blocking' => true, ); if ( null !== $options ) { if ( null !== $options->getTimeout() ) { $args['timeout'] = $options->getTimeout(); } if ( null !== $options->getMaxRedirects() ) { $args['redirection'] = $options->getMaxRedirects(); } } return $args; } /** * Prepares headers for WordPress HTTP API. * * @since 7.0.0 * * @param RequestInterface $request The PSR-7 request. * @return array<string, string> Headers array for WordPress HTTP API. */ private function prepare_headers( RequestInterface $request ): array { $headers = array(); foreach ( $request->getHeaders() as $name => $values ) { $headers[ (string) $name ] = implode( ', ', $values ); } return $headers; } /** * Prepares request body for WordPress HTTP API. * * @since 7.0.0 * * @param RequestInterface $request The PSR-7 request. * @return string|null The request body. */ private function prepare_body( RequestInterface $request ): ?string { $body = $request->getBody(); if ( $body->getSize() === 0 ) { return null; } if ( $body->isSeekable() ) { $body->rewind(); } return (string) $body; } /** * Creates a PSR-7 response from a WordPress HTTP response. * * @since 7.0.0 * * @param array<string, mixed> $wp_response WordPress HTTP API response array. * @return ResponseInterface PSR-7 response. */ private function create_psr_response( array $wp_response ): ResponseInterface { $status_code = wp_remote_retrieve_response_code( $wp_response ); $reason_phrase = wp_remote_retrieve_response_message( $wp_response ); $headers = wp_remote_retrieve_headers( $wp_response ); $body = wp_remote_retrieve_body( $wp_response ); $response = $this->response_factory->createResponse( (int) $status_code, $reason_phrase ); if ( $headers instanceof WP_HTTP_Requests_Response ) { $headers = $headers->get_headers(); } if ( is_array( $headers ) || $headers instanceof Traversable ) { foreach ( $headers as $name => $value ) { $response = $response->withHeader( $name, $value ); } } if ( ! empty( $body ) ) { $stream = $this->stream_factory->createStream( $body ); $response = $response->withBody( $stream ); } return $response; } } adapters/class-wp-ai-client-discovery-strategy.php 0000644 00000002217 15206745041 0016327 0 ustar 00 <?php /** * WP AI Client: WP_AI_Client_Discovery_Strategy class * * @package WordPress * @subpackage AI * @since 7.0.0 */ use WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy; use WordPress\AiClientDependencies\Nyholm\Psr7\Factory\Psr17Factory; use WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface; /** * Discovery strategy for WordPress HTTP client. * * Registers the WordPress HTTP client adapter with the HTTPlug discovery system * so the AI Client SDK can find and use it automatically. * * @since 7.0.0 * @internal Intended only to register WordPress's HTTP client so that the PHP AI Client SDK can use it. * @access private */ class WP_AI_Client_Discovery_Strategy extends AbstractClientDiscoveryStrategy { /** * Creates an instance of the WordPress HTTP client. * * @since 7.0.0 * * @param Psr17Factory $psr17_factory The PSR-17 factory for creating HTTP messages. * @return ClientInterface The PSR-18 HTTP client. */ protected static function createClient( Psr17Factory $psr17_factory ): ClientInterface { return new WP_AI_Client_HTTP_Client( $psr17_factory, $psr17_factory ); } } adapters/error_log 0000644 00000034441 15206745041 0010276 0 ustar 00 [30-May-2026 09:59:34 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [30-May-2026 09:59:37 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 09:59:37 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [30-May-2026 09:59:37 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 09:59:40 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [30-May-2026 09:59:40 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 09:59:41 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 09:59:42 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [30-May-2026 09:59:43 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [30-May-2026 09:59:43 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 09:59:43 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 10:00:14 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [30-May-2026 10:00:17 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 10:00:17 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 10:00:17 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [30-May-2026 10:00:19 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [30-May-2026 10:00:21 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 10:00:21 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 10:00:21 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [30-May-2026 10:00:26 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 10:00:27 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [30-May-2026 20:09:02 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [30-May-2026 20:24:53 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 20:34:24 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 21:20:16 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [30-May-2026 21:29:37 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [30-May-2026 21:34:08 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 21:51:36 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [30-May-2026 21:53:08 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 22:16:54 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 [30-May-2026 22:35:34 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [31-May-2026 00:42:25 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [31-May-2026 00:43:00 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [31-May-2026 01:48:29 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-event-dispatcher.php on line 22 [31-May-2026 01:51:37 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php:22 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-cache.php on line 22 [31-May-2026 01:52:38 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php:29 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php on line 29 [31-May-2026 01:58:48 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy" not found in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php:24 Stack trace: #0 {main} thrown in /home/gzbnyc5/avenuesny.com/wp-includes/ai-client/adapters/class-wp-ai-client-discovery-strategy.php on line 24 class-wp-ai-client-prompt-builder.php 0000644 00000046513 15206745041 0013631 0 ustar 00 <?php /** * WP AI Client: WP_AI_Client_Prompt_Builder class * * @package WordPress * @subpackage AI * @since 7.0.0 */ use WordPress\AiClient\AiClient; use WordPress\AiClient\Builders\PromptBuilder; use WordPress\AiClient\Common\Exception\InvalidArgumentException; use WordPress\AiClient\Common\Exception\TokenLimitReachedException; use WordPress\AiClient\Files\DTO\File; use WordPress\AiClient\Files\Enums\FileTypeEnum; use WordPress\AiClient\Files\Enums\MediaOrientationEnum; use WordPress\AiClient\Messages\DTO\Message; use WordPress\AiClient\Messages\DTO\MessagePart; use WordPress\AiClient\Messages\Enums\ModalityEnum; use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Http\Exception\ClientException; use WordPress\AiClient\Providers\Http\Exception\NetworkException; use WordPress\AiClient\Providers\Http\Exception\ServerException; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum; use WordPress\AiClient\Providers\ProviderRegistry; use WordPress\AiClient\Results\DTO\GenerativeAiResult; use WordPress\AiClient\Tools\DTO\FunctionDeclaration; use WordPress\AiClient\Tools\DTO\FunctionResponse; use WordPress\AiClient\Tools\DTO\WebSearch; /** * Fluent builder for constructing AI prompts, returning WP_Error on failure. * * This class provides a fluent interface for building prompts with various * content types and model configurations. It wraps the PHP AI Client SDK's * PromptBuilder and adds WordPress-specific behavior including WP_Error * handling instead of exceptions, snake_case method naming, and integration * with the Abilities API. * * Only the generating methods will return a WP_Error, to not break the fluent * interface. As soon as any exception is caught in a chain of method calls, * the returned instance will be in an error state, and all subsequent method * calls will be no-ops that just return the same error state instance. Only * when a generating method is called, the WP_Error will be returned. * * @since 7.0.0 * * @phpstan-import-type Prompt from PromptBuilder * * @method self with_text(string $text) Adds text to the current message. * @method self with_file($file, ?string $mimeType = null) Adds a file to the current message. * @method self with_function_response(FunctionResponse $functionResponse) Adds a function response to the current message. * @method self with_message_parts(MessagePart ...$parts) Adds message parts to the current message. * @method self with_history(Message ...$messages) Adds conversation history messages. * @method self using_model(ModelInterface $model) Sets the model to use for generation. * @method self using_model_preference(...$preferredModels) Sets preferred models to evaluate in order. * @method self using_model_config(ModelConfig $config) Sets the model configuration. * @method self using_provider(string $providerIdOrClassName) Sets the provider to use for generation. * @method self using_system_instruction(string $systemInstruction) Sets the system instruction. * @method self using_max_tokens(int $maxTokens) Sets the maximum number of tokens to generate. * @method self using_temperature(float $temperature) Sets the temperature for generation. * @method self using_top_p(float $topP) Sets the top-p value for generation. * @method self using_top_k(int $topK) Sets the top-k value for generation. * @method self using_stop_sequences(string ...$stopSequences) Sets stop sequences for generation. * @method self using_candidate_count(int $candidateCount) Sets the number of candidates to generate. * @method self using_function_declarations(FunctionDeclaration ...$functionDeclarations) Sets the function declarations available to the model. * @method self using_presence_penalty(float $presencePenalty) Sets the presence penalty for generation. * @method self using_frequency_penalty(float $frequencyPenalty) Sets the frequency penalty for generation. * @method self using_web_search(WebSearch $webSearch) Sets the web search configuration. * @method self using_request_options(RequestOptions $options) Sets the request options for HTTP transport. * @method self using_top_logprobs(?int $topLogprobs = null) Sets the top log probabilities configuration. * @method self as_output_mime_type(string $mimeType) Sets the output MIME type. * @method self as_output_schema(array<string, mixed> $schema) Sets the output schema. * @method self as_output_modalities(ModalityEnum ...$modalities) Sets the output modalities. * @method self as_output_file_type(FileTypeEnum $fileType) Sets the output file type. * @method self as_output_media_orientation(MediaOrientationEnum $orientation) Sets the output media orientation. * @method self as_output_media_aspect_ratio(string $aspectRatio) Sets the output media aspect ratio. * @method self as_output_speech_voice(string $voice) Sets the output speech voice. * @method self as_json_response(?array<string, mixed> $schema = null) Configures the prompt for JSON response output. * @method bool|WP_Error is_supported(?CapabilityEnum $capability = null) Checks if the prompt is supported for the given capability. * @method bool is_supported_for_text_generation() Checks if the prompt is supported for text generation. * @method bool is_supported_for_image_generation() Checks if the prompt is supported for image generation. * @method bool is_supported_for_text_to_speech_conversion() Checks if the prompt is supported for text to speech conversion. * @method bool is_supported_for_video_generation() Checks if the prompt is supported for video generation. * @method bool is_supported_for_speech_generation() Checks if the prompt is supported for speech generation. * @method bool is_supported_for_music_generation() Checks if the prompt is supported for music generation. * @method bool is_supported_for_embedding_generation() Checks if the prompt is supported for embedding generation. * @method GenerativeAiResult|WP_Error generate_result(?CapabilityEnum $capability = null) Generates a result from the prompt. * @method GenerativeAiResult|WP_Error generate_text_result() Generates a text result from the prompt. * @method GenerativeAiResult|WP_Error generate_image_result() Generates an image result from the prompt. * @method GenerativeAiResult|WP_Error generate_speech_result() Generates a speech result from the prompt. * @method GenerativeAiResult|WP_Error convert_text_to_speech_result() Converts text to speech and returns the result. * @method GenerativeAiResult|WP_Error generate_video_result() Generates a video result from the prompt. * @method string|WP_Error generate_text() Generates text from the prompt. * @method list<string>|WP_Error generate_texts(?int $candidateCount = null) Generates multiple text candidates from the prompt. * @method File|WP_Error generate_image() Generates an image from the prompt. * @method list<File>|WP_Error generate_images(?int $candidateCount = null) Generates multiple images from the prompt. * @method File|WP_Error convert_text_to_speech() Converts text to speech. * @method list<File>|WP_Error convert_text_to_speeches(?int $candidateCount = null) Converts text to multiple speech outputs. * @method File|WP_Error generate_speech() Generates speech from the prompt. * @method list<File>|WP_Error generate_speeches(?int $candidateCount = null) Generates multiple speech outputs from the prompt. * @method File|WP_Error generate_video() Generates a video from the prompt. * @method list<File>|WP_Error generate_videos(?int $candidateCount = null) Generates multiple videos from the prompt. */ class WP_AI_Client_Prompt_Builder { /** * Wrapped prompt builder instance from the PHP AI Client SDK. * * @since 7.0.0 * @var PromptBuilder */ private PromptBuilder $builder; /** * WordPress error instance, if any error occurred during method calls. * * @since 7.0.0 * @var WP_Error|null */ private ?WP_Error $error = null; /** * List of methods that generate a result from the prompt. * * Structured as a map for faster lookups. * * @since 7.0.0 * @var array<string, bool> */ private static array $generating_methods = array( 'generate_result' => true, 'generate_text_result' => true, 'generate_image_result' => true, 'generate_speech_result' => true, 'convert_text_to_speech_result' => true, 'generate_video_result' => true, 'generate_text' => true, 'generate_texts' => true, 'generate_image' => true, 'generate_images' => true, 'convert_text_to_speech' => true, 'convert_text_to_speeches' => true, 'generate_speech' => true, 'generate_speeches' => true, 'generate_video' => true, 'generate_videos' => true, ); /** * List of methods that check whether the prompt is supported. * * Structured as a map for faster lookups. * * @since 7.0.0 * @var array<string, bool> */ private static array $support_check_methods = array( 'is_supported' => true, 'is_supported_for_text_generation' => true, 'is_supported_for_image_generation' => true, 'is_supported_for_text_to_speech_conversion' => true, 'is_supported_for_video_generation' => true, 'is_supported_for_speech_generation' => true, 'is_supported_for_music_generation' => true, 'is_supported_for_embedding_generation' => true, ); /** * Constructor. * * @since 7.0.0 * * @param ProviderRegistry $registry The provider registry for finding suitable models. * @param Prompt $prompt Optional. Initial prompt content. * A string for simple text prompts, * a MessagePart or Message object for * structured content, an array for a * message array shape, or a list of * parts or messages for multi-turn * conversations. Default null. */ public function __construct( ProviderRegistry $registry, $prompt = null ) { try { $this->builder = new PromptBuilder( $registry, $prompt, AiClient::getEventDispatcher() ); } catch ( Exception $e ) { $this->builder = new PromptBuilder( $registry, null, AiClient::getEventDispatcher() ); $this->error = $this->exception_to_wp_error( $e ); } $default_timeout = 30.0; /** * Filters the default request timeout in seconds for AI Client HTTP requests. * * @since 7.0.0 * * @param float $default_timeout The default timeout in seconds. */ $filtered_default_timeout = apply_filters( 'wp_ai_client_default_request_timeout', $default_timeout ); if ( is_numeric( $filtered_default_timeout ) && (float) $filtered_default_timeout >= 0.0 ) { $default_timeout = (float) $filtered_default_timeout; } else { _doing_it_wrong( __METHOD__, sprintf( /* translators: %s: wp_ai_client_default_request_timeout */ __( 'The %s filter must return a non-negative number.' ), '<code>wp_ai_client_default_request_timeout</code>' ), '7.0.0' ); } $this->builder->usingRequestOptions( RequestOptions::fromArray( array( RequestOptions::KEY_TIMEOUT => $default_timeout, ) ) ); } /** * Registers WordPress abilities as function declarations for the AI model. * * Converts each WP_Ability to a FunctionDeclaration using the wpab__ prefix * naming convention and passes them to the underlying prompt builder. * * @since 7.0.0 * * @param WP_Ability|string ...$abilities The abilities to register, either as WP_Ability objects or ability name strings. * @return self The current instance for method chaining. */ public function using_abilities( ...$abilities ): self { $declarations = array(); foreach ( $abilities as $ability ) { if ( is_string( $ability ) ) { $ability_name = $ability; $ability = wp_get_ability( $ability ); if ( ! $ability ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %s: string value of the ability name. */ __( 'The ability %s was not found.' ), '<code>' . esc_html( $ability_name ) . '</code>' ), '7.0.0' ); continue; } } // This is only here as a sanity check, the method signature should ensure this already. if ( ! $ability instanceof WP_Ability ) { continue; } $function_name = WP_AI_Client_Ability_Function_Resolver::ability_name_to_function_name( $ability->get_name() ); $input_schema = $ability->get_input_schema(); $declarations[] = new FunctionDeclaration( $function_name, $ability->get_description(), ! empty( $input_schema ) ? $input_schema : null ); } if ( ! empty( $declarations ) ) { return $this->using_function_declarations( ...$declarations ); } return $this; } /** * Magic method to proxy snake_case method calls to their PHP AI Client camelCase counterparts. * * This allows WordPress developers to use snake_case naming conventions. It catches * any exceptions thrown, stores them, and returns a WP_Error when a terminate method * is called. * * @since 7.0.0 * * @param string $name The method name in snake_case. * @param array<int, mixed> $arguments The method arguments. * @return mixed The result of the method call. */ public function __call( string $name, array $arguments ) { /* * If an error occurred in a previous method call, either return the error for terminate methods, * or return the same instance for other methods to maintain the fluent interface. */ if ( null !== $this->error ) { if ( self::is_generating_method( $name ) ) { return $this->error; } if ( self::is_support_check_method( $name ) ) { return false; } return $this; } // Check if the prompt should be prevented for is_supported* and generate_*/convert_text_to_speech* methods. if ( self::is_support_check_method( $name ) || self::is_generating_method( $name ) ) { // If AI is not supported, then there's no need to apply the filter as the prompt will be prevented anyway. $is_ai_disabled = ! wp_supports_ai(); $prevent = $is_ai_disabled; if ( ! $prevent ) { /** * Filters whether to prevent the prompt from being executed. * * @since 7.0.0 * * @param bool $prevent Whether to prevent the prompt. Default false. * @param WP_AI_Client_Prompt_Builder $builder A clone of the prompt builder instance (read-only). */ $prevent = (bool) apply_filters( 'wp_ai_client_prevent_prompt', false, clone $this ); } if ( $prevent ) { // For is_supported* methods, return false. if ( self::is_support_check_method( $name ) ) { return false; } $error_message = $is_ai_disabled ? __( 'AI features are not supported in this environment.' ) : __( 'Prompt execution was prevented by a filter.' ); // For generate_* and convert_text_to_speech* methods, create a WP_Error. $this->error = new WP_Error( 'prompt_prevented', $error_message, array( 'status' => 503, ) ); if ( self::is_generating_method( $name ) ) { return $this->error; } return $this; } } try { $callable = $this->get_builder_callable( $name ); $result = $callable( ...$arguments ); // If the result is a PromptBuilder, return the current instance to allow method chaining. if ( $result instanceof PromptBuilder ) { return $this; } return $result; } catch ( Exception $e ) { $this->error = $this->exception_to_wp_error( $e ); if ( self::is_generating_method( $name ) ) { return $this->error; } return $this; } } /** * Converts an exception into a WP_Error with a structured error code and message. * * This method maps different exception types to specific WP_Error codes and HTTP status codes. * The presence of the status codes means these WP_Error objects can be easily used in REST API responses * or other contexts where HTTP semantics are relevant. * * @since 7.0.0 * * @param Exception $e The exception to convert. * @return WP_Error The resulting WP_Error object. */ private function exception_to_wp_error( Exception $e ): WP_Error { if ( $e instanceof NetworkException ) { $error_code = 'prompt_network_error'; $status_code = 503; } elseif ( $e instanceof ClientException ) { // `ClientException` uses HTTP status codes as exception codes, so we can rely on them. $error_code = 'prompt_client_error'; $status_code = $e->getCode() ? $e->getCode() : 400; } elseif ( $e instanceof ServerException ) { // `ServerException` uses HTTP status codes as exception codes, so we can rely on them. $error_code = 'prompt_upstream_server_error'; $status_code = $e->getCode() ? $e->getCode() : 500; } elseif ( $e instanceof TokenLimitReachedException ) { $error_code = 'prompt_token_limit_reached'; $status_code = 400; } elseif ( $e instanceof InvalidArgumentException ) { $error_code = 'prompt_invalid_argument'; $status_code = 400; } else { $error_code = 'prompt_builder_error'; $status_code = 500; } return new WP_Error( $error_code, $e->getMessage(), array( 'status' => $status_code, 'exception_class' => get_class( $e ), ) ); } /** * Checks if a method name is a support check method (is_supported*). * * @since 7.0.0 * * @param string $name The method name. * @return bool True if the method is a support check method, false otherwise. */ private static function is_support_check_method( string $name ): bool { return isset( self::$support_check_methods[ $name ] ); } /** * Checks if a method name is a generating method (generate_*, convert_text_to_speech*). * * @since 7.0.0 * * @param string $name The method name. * @return bool True if the method is a generating method, false otherwise. */ private static function is_generating_method( string $name ): bool { return isset( self::$generating_methods[ $name ] ); } /** * Retrieves a callable for a given PHP AI Client SDK prompt builder method name. * * @since 7.0.0 * * @param string $name The method name in snake_case. * @return callable The callable for the specified method. * * @throws BadMethodCallException If the method does not exist. */ protected function get_builder_callable( string $name ): callable { $camel_case_name = $this->snake_to_camel_case( $name ); $method = array( $this->builder, $camel_case_name ); if ( ! is_callable( $method ) ) { throw new BadMethodCallException( sprintf( /* translators: 1: Method name. 2: Class name. */ __( 'Method %1$s does not exist on %2$s.' ), $name, // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped get_class( $this->builder ) // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped ) ); } return $method; } /** * Converts snake_case to camelCase. * * @since 7.0.0 * * @param string $snake_case The snake_case string. * @return string The camelCase string. */ private function snake_to_camel_case( string $snake_case ): string { $parts = explode( '_', $snake_case ); $camel_case = $parts[0]; $parts_count = count( $parts ); for ( $i = 1; $i < $parts_count; $i++ ) { $camel_case .= ucfirst( $parts[ $i ] ); } return $camel_case; } } class-wp-ai-client-ability-function-resolver.php 0000644 00000014171 15206745041 0015776 0 ustar 00 <?php /** * WP AI Client: WP_AI_Client_Ability_Function_Resolver class * * @package WordPress * @subpackage AI * @since 7.0.0 */ use WordPress\AiClient\Messages\DTO\Message; use WordPress\AiClient\Messages\DTO\MessagePart; use WordPress\AiClient\Messages\DTO\UserMessage; use WordPress\AiClient\Tools\DTO\FunctionCall; use WordPress\AiClient\Tools\DTO\FunctionResponse; /** * Resolves and executes WordPress Abilities API function calls from AI models. * * This class must be instantiated with the specific abilities that the AI model * is allowed to execute, ensuring that only explicitly specified abilities can * be called. This prevents the model from executing arbitrary abilities. * * @since 7.0.0 */ class WP_AI_Client_Ability_Function_Resolver { /** * Prefix used to identify ability function calls. * * @since 7.0.0 * @var string */ private const ABILITY_PREFIX = 'wpab__'; /** * Map of allowed ability names for this instance. * * Keys are ability name strings, values are `true` for O(1) lookup. * * @since 7.0.0 * @var array<string, true> */ private array $allowed_abilities; /** * Constructor. * * @since 7.0.0 * * @param WP_Ability|string ...$abilities The abilities that this resolver is allowed to execute. */ public function __construct( ...$abilities ) { $this->allowed_abilities = array(); foreach ( $abilities as $ability ) { if ( $ability instanceof WP_Ability ) { $this->allowed_abilities[ $ability->get_name() ] = true; } elseif ( is_string( $ability ) ) { $this->allowed_abilities[ $ability ] = true; } } } /** * Checks if a function call is an ability call. * * @since 7.0.0 * * @param FunctionCall $call The function call to check. * @return bool True if the function call is an ability call, false otherwise. */ public function is_ability_call( FunctionCall $call ): bool { $name = $call->getName(); if ( null === $name ) { return false; } return str_starts_with( $name, self::ABILITY_PREFIX ); } /** * Executes a WordPress ability from a function call. * * Only abilities that were specified in the constructor are allowed to be * executed. If the ability is not in the allowed list, an error response * with code `ability_not_allowed` is returned. * * @since 7.0.0 * * @param FunctionCall $call The function call to execute. * @return FunctionResponse The response from executing the ability. */ public function execute_ability( FunctionCall $call ): FunctionResponse { $function_name = $call->getName() ?? 'unknown'; $function_id = $call->getId() ?? 'unknown'; if ( ! $this->is_ability_call( $call ) ) { return new FunctionResponse( $function_id, $function_name, array( 'error' => __( 'Not an ability function call' ), 'code' => 'invalid_ability_call', ) ); } $ability_name = self::function_name_to_ability_name( $function_name ); if ( ! isset( $this->allowed_abilities[ $ability_name ] ) ) { return new FunctionResponse( $function_id, $function_name, array( /* translators: %s: ability name */ 'error' => sprintf( __( 'Ability "%s" was not specified in the allowed abilities list.' ), $ability_name ), 'code' => 'ability_not_allowed', ) ); } $ability = wp_get_ability( $ability_name ); if ( ! $ability instanceof WP_Ability ) { return new FunctionResponse( $function_id, $function_name, array( /* translators: %s: ability name */ 'error' => sprintf( __( 'Ability "%s" not found' ), $ability_name ), 'code' => 'ability_not_found', ) ); } $args = $call->getArgs(); $result = $ability->execute( ! empty( $args ) ? $args : null ); if ( is_wp_error( $result ) ) { return new FunctionResponse( $function_id, $function_name, array( 'error' => $result->get_error_message(), 'code' => $result->get_error_code(), 'data' => $result->get_error_data(), ) ); } return new FunctionResponse( $function_id, $function_name, $result ); } /** * Checks if a message contains any ability function calls. * * @since 7.0.0 * * @param Message $message The message to check. * @return bool True if the message contains ability calls, false otherwise. */ public function has_ability_calls( Message $message ): bool { foreach ( $message->getParts() as $part ) { if ( $part->getType()->isFunctionCall() ) { $function_call = $part->getFunctionCall(); if ( $function_call instanceof FunctionCall && $this->is_ability_call( $function_call ) ) { return true; } } } return false; } /** * Executes all ability function calls in a message. * * @since 7.0.0 * * @param Message $message The message containing function calls. * @return Message A new message with function responses. */ public function execute_abilities( Message $message ): Message { $response_parts = array(); foreach ( $message->getParts() as $part ) { if ( $part->getType()->isFunctionCall() ) { $function_call = $part->getFunctionCall(); if ( $function_call instanceof FunctionCall ) { $function_response = $this->execute_ability( $function_call ); $response_parts[] = new MessagePart( $function_response ); } } } return new UserMessage( $response_parts ); } /** * Converts an ability name to a function name. * * Transforms "tec/create_event" to "wpab__tec__create_event". * * @since 7.0.0 * * @param string $ability_name The ability name to convert. * @return string The function name. */ public static function ability_name_to_function_name( string $ability_name ): string { return self::ABILITY_PREFIX . str_replace( '/', '__', $ability_name ); } /** * Converts a function name to an ability name. * * Transforms "wpab__tec__create_event" to "tec/create_event". * * @since 7.0.0 * * @param string $function_name The function name to convert. * @return string The ability name. */ public static function function_name_to_ability_name( string $function_name ): string { $without_prefix = substr( $function_name, strlen( self::ABILITY_PREFIX ) ); return str_replace( '__', '/', $without_prefix ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.31 | Generation time: 0 |
proxy
|
phpinfo
|
Settings