Skip to content
Open
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
441dad1
Switch our client-side Ability execution over to the new client-side API
dkotter Apr 1, 2026
5ca2efa
Install the @wordpress/abilities dependency and update our type depen…
dkotter Apr 1, 2026
826a995
Fix some new lint errors
dkotter Apr 1, 2026
5b1ffd3
Ensure the core abilities module is loaded
dkotter Apr 1, 2026
ca0c0b9
Remove the unsupported sanitize_callback from our Title Generation in…
dkotter Apr 2, 2026
75bdb74
Remove the unsupported sanitize_callback from our Summarization input…
dkotter Apr 2, 2026
cabf245
Remove the unsupported sanitize_callback from our Review Notes input …
dkotter Apr 2, 2026
a1e61b4
Remove the unsupported sanitize_callback from our Excerpt Generation …
dkotter Apr 2, 2026
cb2b884
Remove the unsupported sanitize_callback from our Alt Text Generation…
dkotter Apr 2, 2026
9af3741
Remove the unsupported sanitize_callback from our Image Prompt Genera…
dkotter Apr 2, 2026
edbc395
Remove the unsupported sanitize_callback from our Image Generation in…
dkotter Apr 2, 2026
23aae6f
Update docs and tests
dkotter Apr 2, 2026
c96ec81
Remove the unsupported sanitize_callback from our Image Import input …
dkotter Apr 2, 2026
9c0b512
Ensure each Experiment that makes an AI request loads the proper clie…
dkotter Apr 2, 2026
fa9c807
Fix an issue where block content is sometimes returned as an object i…
dkotter Apr 2, 2026
2ff2139
Merge branch 'develop' into update/client-ability-execution
dkotter Apr 2, 2026
0136c33
Merge branch 'develop' into update/client-ability-execution
dkotter Apr 3, 2026
d99d512
Merge branch 'develop' into update/client-ability-execution
dkotter Apr 9, 2026
d7a17be
Merge branch 'develop' into update/client-ability-execution
jeffpaul Apr 9, 2026
00836ae
Merge branch 'develop' into update/client-ability-execution
dkotter Apr 9, 2026
b3846a1
Ensure the core abilities module is loaded when using Content Classif…
dkotter Apr 9, 2026
e99ea97
Ensure the core abilities module is loaded when using the Meta Descri…
dkotter Apr 9, 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
15 changes: 6 additions & 9 deletions docs/experiments/alt-text-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,16 @@ array(
'type' => 'object',
'properties' => array(
'attachment_id' => array(
'type' => 'integer',
'sanitize_callback' => 'absint',
'description' => 'The attachment ID of the image to generate alt text for.',
'type' => 'integer',
'description' => 'The attachment ID of the image to generate alt text for.',
),
'image_url' => array(
'type' => 'string',
'sanitize_callback' => array( $this, 'sanitize_image_reference_input' ),
'description' => 'URL or data URI of the image to generate alt text for. Used if attachment_id is not provided.',
'type' => 'string',
'description' => 'URL or data URI of the image to generate alt text for. Used if attachment_id is not provided.',
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_textarea_field',
'description' => 'Optional context about the image or surrounding content to improve alt text relevance.',
'type' => 'string',
'description' => 'Optional context about the image or surrounding content to improve alt text relevance.',
),
),
)
Expand Down
10 changes: 4 additions & 6 deletions docs/experiments/excerpt-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,12 @@ The ability accepts the following input parameters:
```php
array(
'content' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Content to generate an excerpt suggestion for.',
'type' => 'string',
'description' => 'Content to generate an excerpt suggestion for.',
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Additional context to use when generating an excerpt. Can be a string of additional context or a post ID (as string) that will be used to get context from that post. If no content is provided but a valid post ID is used, the content from that post will be used.',
'type' => 'string',
'description' => 'Additional context to use when generating an excerpt. Can be a string of additional context or a post ID (as string) that will be used to get context from that post. If no content is provided but a valid post ID is used, the content from that post will be used.',
),
)
```
Expand Down
65 changes: 26 additions & 39 deletions docs/experiments/image-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,16 @@ array(
'type' => 'object',
'properties' => array(
'content' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The content to use as inspiration for the generated image.',
'type' => 'string',
'description' => 'The content to use as inspiration for the generated image.',
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Any additional context to help generate the prompt. This can either be a string of additional context or can be a post ID that will then be used to get context from that post (if it exists).',
'type' => 'string',
'description' => 'Any additional context to help generate the prompt. This can either be a string of additional context or can be a post ID that will then be used to get context from that post (if it exists).',
),
'style' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Any additional style instructions to apply to the generated image.',
'type' => 'string',
'description' => 'Any additional style instructions to apply to the generated image.',
),
),
'required' => array( 'content' ),
Expand All @@ -141,14 +138,12 @@ array(
'type' => 'object',
'properties' => array(
'prompt' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Prompt used to generate an image.',
'type' => 'string',
'description' => 'Prompt used to generate an image.',
),
'reference' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Optional base64-encoded image to use as a reference for editing.',
'type' => 'string',
'description' => 'Optional base64-encoded image to use as a reference for editing.',
),
),
'required' => array( 'prompt' ),
Expand All @@ -162,34 +157,28 @@ array(
'type' => 'object',
'properties' => array(
'data' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The base64 encoded image data to import into the media library.',
'type' => 'string',
'description' => 'The base64 encoded image data to import into the media library.',
),
'filename' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The filename of the image.',
'type' => 'string',
'description' => 'The filename of the image.',
),
'title' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The title of the image.',
'type' => 'string',
'description' => 'The title of the image.',
),
'description' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The description of the image.',
'type' => 'string',
'description' => 'The description of the image.',
),
'alt_text' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The alt text of the image.',
'type' => 'string',
'description' => 'The alt text of the image.',
),
'mime_type' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The MIME type of the image.',
'type' => 'string',
'description' => 'The MIME type of the image.',
),
'meta' => array(
'type' => 'array',
Expand All @@ -198,14 +187,12 @@ array(
'type' => 'object',
'properties' => array(
'key' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_key',
'description' => 'The key of the meta data.',
'type' => 'string',
'description' => 'The key of the meta data.',
),
'value' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The value of the meta data.',
'type' => 'string',
'description' => 'The value of the meta data.',
),
),
'required' => array( 'key', 'value' ),
Expand Down
18 changes: 7 additions & 11 deletions docs/experiments/review-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,23 +92,19 @@ Blocks with fewer than 20 characters of text content are skipped. The review is
```php
array(
'block_type' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The block type, e.g. core/paragraph, core/heading.',
'type' => 'string',
'description' => 'The block type, e.g. core/paragraph, core/heading.',
),
'block_content' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'The plain-text content of the block to review.',
'type' => 'string',
'description' => 'The plain-text content of the block to review.',
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Surrounding content to improve review relevance.',
'type' => 'string',
'description' => 'Surrounding content to improve review relevance.',
),
'post_id' => array(
'type' => 'integer',
'sanitize_callback' => 'absint',
'type' => 'integer',
'description' => 'ID of the post being reviewed.',
),
'existing_notes' => array(
Expand Down
10 changes: 4 additions & 6 deletions docs/experiments/summarization.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,12 @@ array(
'type' => 'object',
'properties' => array(
'content' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Content to summarize.',
'type' => 'string',
'description' => 'Content to summarize.',
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Additional context to use when summarizing the content. Can be a string of additional context or a post ID (as string) that will be used to get context from that post. If no content is provided but a valid post ID is used, the content from that post will be used.',
'type' => 'string',
'description' => 'Additional context to use when summarizing the content. Can be a string of additional context or a post ID (as string) that will be used to get context from that post. If no content is provided but a valid post ID is used, the content from that post will be used.',
),
'length' => array(
'type' => 'string',
Expand Down
12 changes: 5 additions & 7 deletions includes/Abilities/Excerpt_Generation/Excerpt_Generation.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@ protected function input_schema(): array {
'type' => 'object',
'properties' => array(
'content' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => esc_html__( 'Content to generate an excerpt suggestion for.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'Content to generate an excerpt suggestion for.', 'ai' ),
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => esc_html__( 'Additional context to use when generating an excerpt suggestion for the content. This can either be a string of additional context or can be a post ID that will then be used to get context from that post (if it exists). If no content is provided but a valid post ID is used here, the content from that post will be used.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'Additional context to use when generating an excerpt suggestion for the content. This can either be a string of additional context or can be a post ID that will then be used to get context from that post (if it exists). If no content is provided but a valid post ID is used here, the content from that post will be used.', 'ai' ),
),
),
);
Expand Down Expand Up @@ -96,7 +94,7 @@ protected function execute_callback( $input ) {
}
} else {
$content = normalize_content( $args['content'] ?? '' );
$context = $args['context'] ?? '';
$context = isset( $args['context'] ) ? sanitize_text_field( $args['context'] ) : '';
}

// If we have no content, return an error.
Expand Down
17 changes: 8 additions & 9 deletions includes/Abilities/Image/Alt_Text_Generation.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,16 @@ protected function input_schema(): array {
'type' => 'object',
'properties' => array(
'attachment_id' => array(
'type' => 'integer',
'sanitize_callback' => 'absint',
'description' => esc_html__( 'The attachment ID of the image to generate alt text for.', 'ai' ),
'type' => 'integer',
'description' => esc_html__( 'The attachment ID of the image to generate alt text for.', 'ai' ),
),
'image_url' => array(
'type' => 'string',
'sanitize_callback' => array( $this, 'sanitize_image_reference_input' ),
'description' => esc_html__( 'URL or data URI of the image to generate alt text for. Used if attachment_id is not provided.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'URL or data URI of the image to generate alt text for. Used if attachment_id is not provided.', 'ai' ),
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_textarea_field',
'description' => esc_html__( 'Optional context about the image or surrounding content to improve alt text relevance.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'Optional context about the image or surrounding content to improve alt text relevance.', 'ai' ),
),
'image_meta' => array(
'type' => 'string',
Expand Down Expand Up @@ -160,6 +157,8 @@ protected function get_image_reference( array $args ) {

// If an image URL is provided, get the image from the URL.
if ( ! empty( $args['image_url'] ) ) {
$args['image_url'] = $this->sanitize_image_reference_input( $args['image_url'] );

// Preserve data URIs as-is so the AI client can read the inline bytes.
if ( 0 === strpos( $args['image_url'], 'data:' ) ) {
return $this->prepare_reference_result( $args['image_url'] );
Expand Down
15 changes: 7 additions & 8 deletions includes/Abilities/Image/Generate_Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ protected function input_schema(): array {
'type' => 'object',
'properties' => array(
'prompt' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => esc_html__( 'Prompt used to generate an image.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'Prompt used to generate an image.', 'ai' ),
),
'reference' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => esc_html__( 'Optional base64-encoded image to use as a reference image for edits.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'Optional base64-encoded image to use as a reference image for edits.', 'ai' ),
),
),
'required' => array( 'prompt' ),
Expand Down Expand Up @@ -112,10 +110,11 @@ protected function output_schema(): array {
* @since 0.2.0
*/
protected function execute_callback( $input ) {
$reference_image = ! empty( $input['reference'] ) ? (string) $input['reference'] : null;
$prompt = isset( $input['prompt'] ) ? sanitize_text_field( $input['prompt'] ) : '';
$reference_image = ! empty( $input['reference'] ) ? sanitize_text_field( $input['reference'] ) : null;

// Generate the image.
$result = $this->generate_image( $input['prompt'], $reference_image );
$result = $this->generate_image( $prompt, $reference_image );

// If we have an error, return it.
if ( is_wp_error( $result ) ) {
Expand Down
19 changes: 9 additions & 10 deletions includes/Abilities/Image/Generate_Image_Prompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,16 @@ protected function input_schema(): array {
'type' => 'object',
'properties' => array(
'content' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => esc_html__( 'The content to use as inspiration for the generated image.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'The content to use as inspiration for the generated image.', 'ai' ),
),
'context' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => esc_html__( 'Any additional context to help generate the prompt. This can either be a string of additional context or can be a post ID that will then be used to get context from that post (if it exists).', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'Any additional context to help generate the prompt. This can either be a string of additional context or can be a post ID that will then be used to get context from that post (if it exists).', 'ai' ),
),
'style' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'description' => esc_html__( 'Any additional style instructions to apply to the generated image.', 'ai' ),
'type' => 'string',
'description' => esc_html__( 'Any additional style instructions to apply to the generated image.', 'ai' ),
),
),
'required' => array( 'content' ),
Expand Down Expand Up @@ -80,6 +77,8 @@ protected function execute_callback( $input ) {
),
);

$args['style'] = is_string( $args['style'] ) ? sanitize_text_field( $args['style'] ) : null;

// If a post ID is provided, ensure the post exists before using it.
if ( is_numeric( $args['context'] ) ) {
$post = get_post( (int) $args['context'] );
Expand All @@ -103,7 +102,7 @@ protected function execute_callback( $input ) {
}
} else {
$content = normalize_content( $args['content'] ?? '' );
$context = $args['context'] ?? '';
$context = isset( $args['context'] ) ? sanitize_text_field( $args['context'] ) : '';
}

// If we have no content, return an error.
Expand Down
Loading
Loading