File "AbilitiesDiscovery.php"

Full Path: /home/buyiwexj/public_html/wp-content/plugins/extendify/app/Agent/AbilitiesDiscovery.php
File size: 3.12 KB
MIME-type: text/x-php
Charset: utf-8

<?php

/**
 * Discovers WordPress Abilities registered on the site for the Agent.
 */

namespace Extendify\Agent;

use Extendify\PartnerData;

defined('ABSPATH') || die('No direct access.');

/**
 * Reads the Abilities API (WP 6.9+) and shapes the survivors for the Agent,
 * grouped by category so the backend can route to a category before a tool.
 */
class AbilitiesDiscovery
{
    /**
     * Discover the abilities registered on this install.
     *
     * @return array
     */
    public static function discover()
    {
        if (!function_exists('wp_get_abilities')) {
            return [];
        }

        return self::shape(
            wp_get_abilities(),
            wp_get_ability_categories(),
            PartnerData::setting('agentAbilitiesAllowlist')
        );
    }

    /**
     * Keep only REST-exposed abilities, then group their descriptors under the
     * categories that hold at least one.
     *
     * No permission filtering here: an ability's permission_callback often turns
     * on the specific input (e.g. edit_post for a given post id) which discovery
     * doesn't have, so the /run endpoint enforces permission at call time.
     *
     * @param array $abilities WP_Ability objects from wp_get_abilities().
     * @param array $categories WP_Ability_Category objects from wp_get_ability_categories().
     * @param array|null $allowlist Namespace prefixes to keep; null keeps every namespace.
     * @return array
     */
    public static function shape(array $abilities, array $categories = [], $allowlist = null)
    {
        $allowed = array_filter($abilities, function ($ability) use ($allowlist) {
            if (!$ability->get_meta_item('show_in_rest')) {
                return false;
            }

            if ($allowlist === null) {
                return true;
            }

            return in_array(explode('/', $ability->get_name())[0], $allowlist, true);
        });

        $byCategory = [];
        foreach ($allowed as $ability) {
            $meta = $ability->get_meta();
            $name = $ability->get_name();
            $byCategory[$ability->get_category()][] = [
                'name' => $name,
                'label' => $ability->get_label(),
                'description' => $ability->get_description(),
                'inputSchema' => $ability->get_input_schema(),
                'annotations' => $meta['annotations'] ?? null,
                'runHref' => \rest_url('wp-abilities/v1/abilities/' . $name . '/run'),
            ];
        }

        $categoryMeta = [];
        foreach ($categories as $category) {
            $categoryMeta[$category->get_slug()] = [
                'label' => $category->get_label(),
                'description' => $category->get_description(),
            ];
        }

        $result = [];
        foreach ($byCategory as $slug => $abilitiesInCategory) {
            $result[] = [
                'slug' => $slug,
                'label' => $categoryMeta[$slug]['label'] ?? $slug,
                'description' => $categoryMeta[$slug]['description'] ?? '',
                'abilities' => $abilitiesInCategory,
            ];
        }

        return $result;
    }
}