[wp-trac] [WordPress Trac] #65097: Add action to `WP_AI_Client_Prompt_Builder` for builder-level configuration injection

WordPress Trac noreply at wordpress.org
Sat Apr 18 08:45:07 UTC 2026


#65097: Add action to `WP_AI_Client_Prompt_Builder` for builder-level configuration
injection
-----------------------------+-----------------------------------
 Reporter:  takshil          |      Owner:  (none)
     Type:  feature request  |     Status:  new
 Priority:  normal           |  Milestone:  Awaiting Review
Component:  AI               |    Version:
 Severity:  normal           |   Keywords:  2nd-opinion has-patch
  Focuses:                   |
-----------------------------+-----------------------------------
 == Problem ==

 Currently, model selection happens in one of two places:

 1. '''Inside the SDK / connector''' - provider-default model ordering. Its
 useful but provider-scoped, cannot express ''cross-provider'' preferences
 like "use OpenAI for text, Mistral for images."
 2. '''Inside each consumer plugin''' - hardcoded `using_model_preference(
 'gpt-5.4', 'claude-sonnet-4-6' )`. Fragmented, opaque to site owners, no
 shared coordination.

 There is no third place - no site-owner-controlled layer that applies
 across all consumer plugins. A standalone "preferences" plugin can store
 the user's choices but has no way to inject them into builders constructed
 elsewhere, because no construction time hook exists.


 == Proposed solution ==

 Add one action at the end of `WP_AI_Client_Prompt_Builder::__construct()`,
 immediately after the existing default-timeout block:

 {{{#!php
 <?php
 // In wp-includes/ai-client/class-wp-ai-client-prompt-builder.php

 /**
  * Fires after a prompt builder is constructed, before any caller
 chaining.
  *
  * Allows plugins to apply default configuration that callers can still
 override via subsequent
  * fluent method calls. Because this fires at construction, any chain
 applied
  * by the caller takes precedence per the SDK's first-match resolution.
  *
  * @since 7.x.0
  *
  * @param WP_AI_Client_Prompt_Builder $builder The newly constructed
 builder.
  * @param mixed                       $prompt  The initial prompt content.
  */
 do_action_ref_array( 'wp_ai_client_prompt_builder_init', array( $this,
 $prompt ) );
 }}}

 === Caller precedence is automatic ===

 {{{
 1. Core constructs builder
 2. wp_ai_client_default_request_timeout fires → sets timeout
 3. wp_ai_client_prompt_builder_init fires → preferences plugin chains
    ->using_model_preference('gpt-5.4', 'mistral-image-v1', ...)
 4. Builder returns to the caller
 5. Caller chains its own potentially by a plugin allowing user's
 preferences
    to be set with a UI->using_model_preference('claude-sonnet-4-6').
    Could be a separate plugin for now, I have some ideas.
 6. SDK's first-match resolution at generate_*() time picks the first model
    that (a) supports the requested capability and (b) has credentials.
    The caller's explicit preference wins because it's evaluated first.
 }}}

 == Why an Action? ==

 It comes down to what listeners will dominantly do:

 - Mutate via `->using_model_preference()` chains → action is the cleaner
 fit (no return tax, natural accumulation)
 - Replace/decorate the builder → filter is required

 Going towards `pre_get_posts` precedent. Core's go-to hook for "mutate a
 fluent/builder-like object" is an action, not a filter, precisely because
 filtering a stateful mutable object invites bugs. This is the closest
 analog I thought of in core. Though open to discussion for filter if the
 AI team prefers consistency with the existing two filters in this file

 == Discussion ==

 * Slack: WordPress.org `#core-ai`, thread starting 2026-04-17
 (https://wordpress.slack.com/archives/C08TJ8BPULS/p1776411977337179).

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/65097>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list