Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0491146
Adds Abilities Explorer
karmatosed Oct 31, 2025
cd33025
Merge branch 'trunk' into TRY/abilitiesexplorer
JasonTheAdams Nov 13, 2025
7948747
Update fixes as suggested in review
karmatosed Nov 14, 2025
6322322
Update as review
karmatosed Nov 14, 2025
544903e
Remove additional checks
karmatosed Nov 26, 2025
e40898b
Merge remote-tracking branch 'origin/develop' into pr/karmatosed/63
justlevine Jan 10, 2026
280efbf
chore: cleanup docblocks
justlevine Jan 10, 2026
86d7754
chore: fix type errors (excl `missingType.iterableValue`)
justlevine Jan 10, 2026
4c52884
Merge branch 'develop' into TRY/abilitiesexplorer
justlevine Jan 12, 2026
6200af8
Merge branch 'develop' into TRY/abilitiesexplorer
justlevine Jan 13, 2026
fc7bcf0
Merge branch 'develop' into TRY/abilitiesexplorer
dkotter Jan 15, 2026
085e594
Move the JS and CSS file into the src directory, build those via webp…
dkotter Jan 15, 2026
eadf439
Ensure the localized data our script relies on actually exists. Fix l…
dkotter Jan 15, 2026
841a7e5
Update since statements to match the format we expect when we replace…
dkotter Jan 15, 2026
a0aeb38
Fix all PHPCS and PHPStan errors
dkotter Jan 15, 2026
37fb4f9
Rename from feature to experiment
dkotter Jan 15, 2026
0884763
Add developer documentation
dkotter Jan 15, 2026
6dc0d4a
Add unit tests
dkotter Jan 15, 2026
69e5faf
Add E2E tests
dkotter Jan 15, 2026
6edc024
Move the menu item from top-level to be nested under the Tools menu. …
dkotter Jan 20, 2026
fb4d456
Fix unit test
dkotter Jan 20, 2026
1c00879
Update the Plugin Check action to v1.1.5
dkotter Jan 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/plugin-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
run: npm run build

- name: Run plugin check
uses: wordpress/plugin-check-action@ec9b3fe9beaa76bcc4510b7ba2cb5855a5f80f3f # v1.1.4
uses: wordpress/plugin-check-action@6f5a57e173c065a394b78688f75df543e4011902 # v1.1.5
with:
wp-version: 'latest'
# Exclude file_type because of the dev files present in the repository.
Expand Down
143 changes: 143 additions & 0 deletions docs/experiments/abilities-explorer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Abilities Explorer

## Summary

The Abilities Explorer experiment provides an admin interface for discovering, inspecting, testing, and documenting all abilities registered via the WordPress Abilities API. It adds a menu item ("Abilities Explorer") under the "Tools" menu in the WordPress admin that displays a searchable, filterable table of all registered abilities with the ability to view details and invoke abilities directly from the UI.

## Overview

### For End Users

When enabled, the Abilities Explorer adds an "Abilities Explorer" menu item under the "Tools" menu in the WordPress admin sidebar. This provides:

**Key Features:**

- Dashboard with statistics showing total abilities by provider (Core, Plugin, Theme)
- Searchable, sortable table of all registered abilities
- Filter abilities by provider type
- Detailed view for each ability showing input/output schemas
- Built-in test runner to invoke abilities with custom JSON input
- JSON validation against input schemas
- Copy-to-clipboard functionality for schemas

### For Developers

The experiment consists of four main classes:

1. **Abilities_Explorer** (`Abilities_Explorer.php`): Main experiment class handling registration and asset loading
2. **Admin_Page** (`Admin_Page.php`): Manages admin menu, page rendering, and AJAX handlers
3. **Ability_Handler** (`Ability_Handler.php`): Interfaces with the WordPress Abilities API to fetch, format, validate, and invoke abilities
4. **Ability_Table** (`Ability_Table.php`): Extends `WP_List_Table` for the abilities listing

## Architecture & Implementation

### Key Hooks & Entry Points

- `WordPress\AI\Experiments\Abilities_Explorer\Abilities_Explorer::register()` wires everything once enabled:
- `admin_enqueue_scripts` → enqueues JS/CSS on the `toplevel_page_ai-abilities-explorer` screen
- `admin_menu` → adds the top-level "Abilities" menu page
- `wp_ajax_ai_ability_explorer_invoke` → handles AJAX ability invocation

### Assets & Data Flow

1. **PHP Side:**
- `enqueue_assets()` loads `experiments/abilities-explorer` bundle and localizes `window.AbilityExplorer` with:
- `enabled`: Whether the experiment is enabled
- `ajaxUrl`: WordPress AJAX URL
- `nonce`: Security nonce for AJAX requests
- `strings`: Localized UI strings

2. **JavaScript Side:**
- Handles test runner functionality (invoke, validate, clear)
- Real-time JSON validation in the input textarea
- Copy-to-clipboard for schemas
- Auto-formatting of JSON input

### Admin Page Views

The admin page supports three views:

1. **List View** (`action=list`, default): Statistics dashboard + searchable table
2. **Detail View** (`action=view&ability=slug`): Full ability details with schemas
3. **Test Runner** (`action=test&ability=slug`): Interactive ability testing interface

### Provider Detection

Abilities are categorized by provider:

- **Core**: Abilities with `wordpress`, `wp`, or `core` namespace prefix
- **Theme**: Abilities matching the active theme's stylesheet or template name
- **Plugin**: All other abilities (default)

### Input Validation

The experiment performs JSON Schema validation:

- Required field checking
- Type validation (string, number, integer, boolean, array, object)
- Real-time JSON syntax validation in the UI

## Using the Test Runner

### Testing an Ability

1. Navigate to **Abilities Explorer** in the "Tools" menu in the admin menu
2. Find the ability you want to test
3. Click the **Test** button
4. Edit the JSON input (pre-populated with example values from the schema)
5. Click **Validate Input** to check JSON syntax and schema compliance
6. Click **Invoke Ability** to execute
7. View the result in the Result section

### Example Input Generation

The test runner automatically generates example input based on the ability's input schema:

- Uses `default` values if specified
- Falls back to `example` values
- Generates type-appropriate defaults (empty string, 0, false, empty array/object)

## Permissions

- Requires `manage_options` capability to access the admin page
- AJAX requests verify nonce and capability before invoking abilities

## Testing

### Manual Testing

1. **Enable the experiment:**
- Go to `Settings → AI Experiments`
- Toggle **Abilities Explorer** to enabled

2. **Test the list view:**
- Navigate to **Abilities Explorer** in the "Tools" menu in the admin menu
- Verify statistics are displayed
- Search for abilities by name or description
- Filter by provider type
- Sort columns

3. **Test the detail view:**
- Click on an ability name or **View** button
- Verify input/output schemas are displayed
- Test copy buttons

4. **Test the test runner:**
- Click **Test** on any ability
- Modify the JSON input
- Click **Validate Input**
- Click **Invoke Ability**
- Verify results are displayed

## Notes & Considerations

### Requirements

- Requires the WordPress Abilities API (`wp_get_abilities`, `wp_get_ability` functions)
- Users must have `manage_options` capability

### Limitations

- Provider detection is heuristic-based and may not be accurate for all abilities
- Input validation is basic JSON Schema validation (required fields, types)
- Does not support nested object validation
1 change: 1 addition & 0 deletions includes/Experiment_Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
*
* @param \WordPress\AI\Experiment_Registry $registry The experiment registry instance.
*/
do_action( 'ai_experiments_register_experiments', $this->registry );

Check warning on line 94 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_register_experiments".
}

/**
Expand All @@ -104,6 +104,7 @@
*/
private function get_default_experiments(): array {
$experiment_classes = array(
\WordPress\AI\Experiments\Abilities_Explorer\Abilities_Explorer::class,
\WordPress\AI\Experiments\Excerpt_Generation\Excerpt_Generation::class,
\WordPress\AI\Experiments\Image_Generation\Image_Generation::class,
\WordPress\AI\Experiments\Summarization\Summarization::class,
Expand All @@ -120,7 +121,7 @@
*
* @param array $experiment_classes Array of experiment class names or instances.
*/
$items = apply_filters( 'ai_experiments_default_experiment_classes', $experiment_classes );

Check warning on line 124 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_default_experiment_classes".

$experiments = array();
foreach ( $items as $item ) {
Expand Down Expand Up @@ -191,7 +192,7 @@
*
* @param bool $enabled Whether to enable AI experiments.
*/
$experiments_enabled = apply_filters( 'ai_experiments_enabled', true );

Check warning on line 195 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_enabled".

if ( ! $experiments_enabled ) {
$this->initialized = true;
Expand All @@ -213,7 +214,7 @@
*
* @since 0.1.0
*/
do_action( 'ai_experiments_initialized' );

Check warning on line 217 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_initialized".

$this->initialized = true;
}
Expand Down
86 changes: 86 additions & 0 deletions includes/Experiments/Abilities_Explorer/Abilities_Explorer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php
/**
* Abilities Explorer Experiment
*
* Discover, inspect, test, and document all abilities
* registered via the WordPress Abilities API.
*
* @package WordPress\AI\Experiments\Abilities_Explorer
* @since x.x.x
*/

namespace WordPress\AI\Experiments\Abilities_Explorer;

use WordPress\AI\Abstracts\Abstract_Experiment;
use WordPress\AI\Asset_Loader;

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

/**
* Abilities Explorer Experiment Class.
*
* Provides a comprehensive interface for exploring
* the WordPress Abilities API.
*
* @since x.x.x
*/
class Abilities_Explorer extends Abstract_Experiment {
/**
* {@inheritDoc}
*/
protected function load_experiment_metadata(): array {
return array(
'id' => 'abilities-explorer',
'label' => __( 'Abilities Explorer', 'ai' ),
'description' => __( 'Discover, inspect, test, and document all abilities registered via the WordPress Abilities API.', 'ai' ),
);
}

/**
* {@inheritDoc}
*/
public function register(): void {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );

// @todo: evaluate standardization after triaging existing comments.
$admin_page = new Admin_Page();
$admin_page->init();
}

/**
* Enqueues and localizes the admin script and styles.
*
* @since x.x.x
*
* @param string $hook_suffix The current admin page hook suffix.
*/
public function enqueue_assets( string $hook_suffix ): void {
// Load asset in Abilities Explorer page only.
if ( 'tools_page_ai-abilities-explorer' !== $hook_suffix ) {
return;
}

Asset_Loader::enqueue_script( 'abilities_explorer', 'experiments/abilities-explorer' );
Asset_Loader::enqueue_style( 'abilities_explorer', 'experiments/abilities-explorer' );
Asset_Loader::localize_script(
'abilities_explorer',
'AbilityExplorer',
array(
'enabled' => $this->is_enabled(),
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'ai_ability_explorer_invoke' ),
'strings' => array(
'invoking' => esc_html__( 'Invoking ability...', 'ai' ),
'success' => esc_html__( 'Success!', 'ai' ),
'error' => esc_html__( 'Error', 'ai' ),
'invalidJson' => esc_html__( 'Invalid JSON input', 'ai' ),
'confirmInvoke' => esc_html__( 'Are you sure you want to invoke this ability?', 'ai' ),
'copySuccess' => esc_html__( 'Copied to clipboard!', 'ai' ),
'copyError' => esc_html__( 'Failed to copy', 'ai' ),
),
)
);
}
}
Loading
Loading