Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
1479dc5
feat: adds tools for importing PHP AI Client
JasonTheAdams Feb 5, 2026
2c842f1
feat: adds php-ai-client to includes
JasonTheAdams Feb 5, 2026
99efae9
feat: adds ai client
JasonTheAdams Feb 6, 2026
1c07c3e
refactor: moves prompt builder and renames directory
JasonTheAdams Feb 6, 2026
23f1af0
fix: handles support methods in an error state
JasonTheAdams Feb 6, 2026
42197b5
refactor: namespaces PSR classes and corrects versions
JasonTheAdams Feb 6, 2026
8a9d2c6
feat: adds wp_ai_client_prompt function
JasonTheAdams Feb 7, 2026
56c6873
refactor: corrects formatting issues
JasonTheAdams Feb 7, 2026
a5bd792
refactor: adds and runs third-party tree-shaking
JasonTheAdams Feb 11, 2026
242f9f9
test: corrects PHP 8.5 compatibility
JasonTheAdams Feb 11, 2026
7caa159
test: corrects formatting issues
JasonTheAdams Feb 11, 2026
0edbfef
test: adjusts reflection accessibility for PHP compatibility
JasonTheAdams Feb 11, 2026
ebbdc54
refactor: removes unnecessary polyfills
JasonTheAdams Feb 11, 2026
278f753
fix: adds missing translation functions and comments
JasonTheAdams Feb 11, 2026
85b1916
test: adds ai client util tests
JasonTheAdams Feb 11, 2026
c494c59
feat: adds AI settings screen
JasonTheAdams Feb 11, 2026
0e78c62
Adjust path filtering for code coverage reports.
desrosj Feb 12, 2026
327a0e9
feat: ports JS + REST portions of AI client
JasonTheAdams Feb 12, 2026
1e2d52c
Merge branch 'trunk' into add/wp-ai-client
felixarntz Feb 14, 2026
9626b32
chore: explicitly lays out $prompt types
JasonTheAdams Feb 16, 2026
62b33aa
feat: locks in only supported stream from file mode
JasonTheAdams Feb 19, 2026
52d4963
refactor: simplifies to using array_find
JasonTheAdams Feb 19, 2026
472f69f
test: adds Prompt_Builder snake case test
JasonTheAdams Feb 20, 2026
b4f9bd7
test: fixes using_abilities tests
JasonTheAdams Feb 20, 2026
9c3b25e
fix: correctly identifies falsey cached values
JasonTheAdams Feb 20, 2026
d708bd2
refactor: moves function resolver and renames ai client folder
JasonTheAdams Feb 20, 2026
97f8598
refactor: switches to wp_safe_remote_request
JasonTheAdams Feb 20, 2026
9e0ebcc
refactor: uses str_starts_with to simplify
JasonTheAdams Feb 20, 2026
76bc7ba
Merge branch 'trunk' into add/wp-ai-client
felixarntz Feb 20, 2026
9364aca
Move AI client initialization out of require file block.
felixarntz Feb 20, 2026
87c0400
Add correct ticket annotations for tests.
felixarntz Feb 20, 2026
d97a86a
Translate messages from failed ability lookup or execution.
felixarntz Feb 20, 2026
582d0d0
Remove unnecessary X-Stream header exclusion.
felixarntz Feb 20, 2026
9098a6e
Yoda.
felixarntz Feb 20, 2026
5f3c5be
Mark infra classes as private.
felixarntz Feb 20, 2026
00ef1b8
Clean up abilities during testing.
felixarntz Feb 20, 2026
0e8a5dc
Make function_name_to_ability_name public.
felixarntz Feb 20, 2026
e8a2a2f
Add warning if invalid ability slug is passed to using_abilities.
felixarntz Feb 20, 2026
0774f6f
feat: always clones php ai client
JasonTheAdams Feb 20, 2026
c58351d
feat: updates PHP AI Client to 1.1.0
JasonTheAdams Feb 20, 2026
7f94810
refactor: uses new PHP AI Client http discovery system
JasonTheAdams Feb 20, 2026
76af7a8
test: fixes failing test
JasonTheAdams Feb 20, 2026
b5baa00
refactor: moves all ai-client classes into ai-client directory
JasonTheAdams Feb 20, 2026
6fa12cb
chore: adds php ai client tool readme
JasonTheAdams Feb 20, 2026
a2852ac
Merge branch 'add/wp-ai-client' into add/ai-settings-screen
JasonTheAdams Feb 20, 2026
51b69af
Merge branch 'add/ai-settings-screen' into add/ai-client-rest
JasonTheAdams Feb 20, 2026
18eba37
fix: registers settings in correct place
JasonTheAdams Feb 20, 2026
27cf7cf
Merge branch 'trunk' into add/ai-settings-screen
JasonTheAdams Feb 20, 2026
1bf9bc6
chore: corrects coverage file
JasonTheAdams Feb 20, 2026
0232558
Merge branch 'add/ai-settings-screen' into add/ai-client-rest
JasonTheAdams Feb 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
833 changes: 833 additions & 0 deletions src/js/_enqueues/wp/ai-client/builders/prompt-builder.js

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions src/js/_enqueues/wp/ai-client/enums.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Constants for PHP AI Client SDK Enums.
*
* @since 7.0.0
*
* @package WordPress
* @subpackage AI
*/

export const FileType = {
INLINE: 'inline',
REMOTE: 'remote',
};

export const MediaOrientation = {
SQUARE: 'square',
LANDSCAPE: 'landscape',
PORTRAIT: 'portrait',
};

export const FinishReason = {
STOP: 'stop',
LENGTH: 'length',
CONTENT_FILTER: 'content_filter',
TOOL_CALLS: 'tool_calls',
ERROR: 'error',
};

export const OperationState = {
STARTING: 'starting',
PROCESSING: 'processing',
SUCCEEDED: 'succeeded',
FAILED: 'failed',
CANCELED: 'canceled',
};

export const ToolType = {
FUNCTION_DECLARATIONS: 'function_declarations',
WEB_SEARCH: 'web_search',
};

export const ProviderType = {
CLOUD: 'cloud',
SERVER: 'server',
CLIENT: 'client',
};

export const MessagePartType = {
TEXT: 'text',
FILE: 'file',
FUNCTION_CALL: 'function_call',
FUNCTION_RESPONSE: 'function_response',
};

export const MessagePartChannel = {
CONTENT: 'content',
THOUGHT: 'thought',
};

export const Modality = {
TEXT: 'text',
DOCUMENT: 'document',
IMAGE: 'image',
AUDIO: 'audio',
VIDEO: 'video',
};

export const MessageRole = {
USER: 'user',
MODEL: 'model',
};

export const Capability = {
TEXT_GENERATION: 'text_generation',
IMAGE_GENERATION: 'image_generation',
TEXT_TO_SPEECH_CONVERSION: 'text_to_speech_conversion',
SPEECH_GENERATION: 'speech_generation',
MUSIC_GENERATION: 'music_generation',
VIDEO_GENERATION: 'video_generation',
EMBEDDING_GENERATION: 'embedding_generation',
CHAT_HISTORY: 'chat_history',
};
183 changes: 183 additions & 0 deletions src/js/_enqueues/wp/ai-client/files/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/**
* File wrapper for AI client files.
*
* @since 7.0.0
*
* @package WordPress
* @subpackage AI
*/

import { FileType } from '../enums';

/**
* Represents a file in the AI client.
*
* @since 7.0.0
*/
export class File {
/**
* Constructor.
*
* @since 7.0.0
*
* @param {Object} file The raw file object.
*/
constructor( file ) {
this._file = file;
}

/**
* Gets the type of file storage.
*
* @since 7.0.0
*
* @return {string} The file type.
*/
get fileType() {
return this._file.fileType;
}

/**
* Gets the MIME type of the file.
*
* @since 7.0.0
*
* @return {string} The MIME type.
*/
get mimeType() {
return this._file.mimeType;
}

/**
* Gets the URL for remote files.
*
* @since 7.0.0
*
* @return {string|undefined} The URL.
*/
get url() {
return this._file.url;
}

/**
* Gets the base64 data for inline files.
*
* @since 7.0.0
*
* @return {string|undefined} The base64 data.
*/
get base64Data() {
return this._file.base64Data;
}

/**
* Checks if the file is an inline file.
*
* @since 7.0.0
*
* @return {boolean} True if the file is inline.
*/
isInline() {
return this.fileType === FileType.INLINE;
}

/**
* Checks if the file is a remote file.
*
* @since 7.0.0
*
* @return {boolean} True if the file is remote.
*/
isRemote() {
return this.fileType === FileType.REMOTE;
}

/**
* Gets the data as a data URI for inline files.
*
* @since 7.0.0
*
* @return {string|undefined} The data URI.
*/
getDataUri() {
if ( ! this.base64Data ) {
return undefined;
}

return `data:${ this.mimeType };base64,${ this.base64Data }`;
}

/**
* Checks if the file is a video.
*
* @since 7.0.0
*
* @return {boolean} True if the file is a video.
*/
isVideo() {
return this.mimeType.startsWith( 'video/' );
}

/**
* Checks if the file is an image.
*
* @since 7.0.0
*
* @return {boolean} True if the file is an image.
*/
isImage() {
return this.mimeType.startsWith( 'image/' );
}

/**
* Checks if the file is audio.
*
* @since 7.0.0
*
* @return {boolean} True if the file is audio.
*/
isAudio() {
return this.mimeType.startsWith( 'audio/' );
}

/**
* Checks if the file is text.
*
* @since 7.0.0
*
* @return {boolean} True if the file is text.
*/
isText() {
return this.mimeType.startsWith( 'text/' );
}

/**
* Checks if the file is a document.
*
* @since 7.0.0
*
* @return {boolean} True if the file is a document.
*/
isDocument() {
return (
this.mimeType === 'application/pdf' ||
this.mimeType.startsWith( 'application/msword' ) ||
this.mimeType.startsWith(
'application/vnd.openxmlformats-officedocument'
) ||
this.mimeType.startsWith( 'application/vnd.ms-' )
);
}

/**
* Checks if the file is a specific MIME type.
*
* @since 7.0.0
*
* @param {string} type The mime type to check.
* @return {boolean} True if the file is of the specified type.
*/
isMimeType( type ) {
return this.mimeType.startsWith( type + '/' ) || this.mimeType === type;
}
}
60 changes: 60 additions & 0 deletions src/js/_enqueues/wp/ai-client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* WordPress AI Client - Client-side API.
*
* @since 7.0.0
*
* @output wp-includes/js/dist/ai-client.js
*
* @package WordPress
* @subpackage AI
*/

import { PromptBuilder } from './builders/prompt-builder';
import {
getProviders,
getProvider,
getProviderModels,
getProviderModel,
} from './providers/api';
import { store } from './providers/store';
import * as enums from './enums';

/**
* Creates a new prompt builder for fluent API usage.
*
* @since 7.0.0
*
* @param {string|Object|Array} [promptInput] Optional initial prompt content.
* @return {PromptBuilder} The prompt builder instance.
*/
export function prompt( promptInput ) {
return new PromptBuilder( promptInput );
}

export {
getProviders,
getProvider,
getProviderModels,
getProviderModel,
store,
enums,
};

// Expose the API in the global `wp.aiClient` namespace for external use.
const AiClient = {
prompt,
getProviders,
getProvider,
getProviderModels,
getProviderModel,
store,
enums,
};

if (
typeof window !== 'undefined' &&
'wp' in window &&
typeof window.wp === 'object'
) {
window.wp.aiClient = AiClient;
}
60 changes: 60 additions & 0 deletions src/js/_enqueues/wp/ai-client/providers/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Provider API functions.
*
* @since 7.0.0
*
* @package WordPress
* @subpackage AI
*/

import { resolveSelect } from '@wordpress/data';
import { store } from './store';

/**
* Gets all registered AI providers.
*
* @since 7.0.0
*
* @return {Promise<Array>} Promise resolving to array of providers.
*/
export async function getProviders() {
return await resolveSelect( store ).getProviders();
}

/**
* Gets a specific provider by its ID.
*
* @since 7.0.0
*
* @param {string} id Provider ID.
* @return {Promise<Object|undefined>} Promise resolving to provider object, or undefined if not found.
*/
export async function getProvider( id ) {
return await resolveSelect( store ).getProvider( id );
}

/**
* Gets all models for a specific provider.
*
* @since 7.0.0
*
* @param {string} providerId Provider ID.
* @return {Promise<Array>} Promise resolving to array of models for the provider.
*/
export async function getProviderModels( providerId ) {
return await resolveSelect( store ).getProviderModels( providerId );
}

/**
* Gets a specific model by its ID for a provider.
*
* @since 7.0.0
*
* @param {string} providerId Provider ID.
* @param {string} modelId Model ID.
* @return {Promise<Object|undefined>} Promise resolving to model object, or undefined if not found.
*/
export async function getProviderModel( providerId, modelId ) {
const models = await resolveSelect( store ).getProviderModels( providerId );
return models.find( ( model ) => model.id === modelId );
}
Loading
Loading