[wp-trac] [WordPress Trac] #64935: Hooks do not fire for wp_ai_client_prompt() flows.
WordPress Trac
noreply at wordpress.org
Mon Mar 23 22:28:52 UTC 2026
#64935: Hooks do not fire for wp_ai_client_prompt() flows.
--------------------------+-----------------------------
Reporter: shadyvb | Owner: (none)
Type: defect (bug) | Status: new
Priority: normal | Milestone: Awaiting Review
Component: AI | Version:
Severity: normal | Keywords: has-patch
Focuses: |
--------------------------+-----------------------------
**TL;DR:** Actions `wp_ai_client_before_generate_result` and
`wp_ai_client_after_generate_result` do not fire for
`wp_ai_client_prompt()` flows. They do fire for `AiClient::prompt()` (or
any `PromptBuilder` constructed with the third argument).
**Summary**
Core registers a PSR-14 event dispatcher on `WordPress\AiClient\AiClient`
and ships `WP_AI_Client_Event_Dispatcher`, which maps SDK lifecycle events
to the documented actions `wp_ai_client_before_generate_result` and
`wp_ai_client_after_generate_result`.
The documented PHP entry point `wp_ai_client_prompt()` returns
`WP_AI_Client_Prompt_Builder`, which constructs
`WordPress\AiClient\Builders\PromptBuilder` without the optional third
constructor argument (`EventDispatcherInterface`). The SDK only dispatches
lifecycle events when that per-instance property is non-null; it does not
fall back to `AiClient::getEventDispatcher()`.
Result: for the primary WordPress API (`wp_ai_client_prompt()` →
`generate_*`), the before/after actions never run, contradicting the
docblocks on `WP_AI_Client_Event_Dispatcher` and developer expectations.
Using `AiClient::prompt()` (SDK) does pass `self::$eventDispatcher` into
`PromptBuilder`, so the same global dispatcher works there — the bug is
specific to the core wrapper path.
**Execution flow (now)**
- `wp-settings.php` calls
`WordPress\AiClient\AiClient::setEventDispatcher( new
WP_AI_Client_Event_Dispatcher() );` — static dispatcher is set.
- `wp_ai_client_prompt( $prompt )` (`wp-includes/ai-client.php`) does `new
WP_AI_Client_Prompt_Builder( AiClient::defaultRegistry(), $prompt )`.
- `WP_AI_Client_Prompt_Builder::__construct()` does `new PromptBuilder(
$registry, $prompt )` — two arguments only (no event dispatcher instance)
(and the same in the catch path with `new PromptBuilder( $registry ))`.
- `PromptBuilder::generateResult()` calls `dispatchEvent()` which no-ops
when `$this->eventDispatcher === null`.
- `WP_AI_Client_Event_Dispatcher::dispatch()` is never invoked for this
path → do_action( 'wp_ai_client_before_generate_result' ) /
wp_ai_client_after_generate_result never run.
In contrast: `AiClient::prompt()` does: `new PromptBuilder( $registry ??
self::defaultRegistry(), $prompt, self::$eventDispatcher );`, and then
those actions are fired.
**Expected behavior**
Any code path documented for extension via
`wp_ai_client_before_generate_result` /
`wp_ai_client_after_generate_result` should fire when using
`wp_ai_client_prompt()` and terminating generation methods
(`generate_text_result()`, etc.), assuming core has bootstrapped the
default dispatcher (as in `wp-settings.php`).
**Actual behavior**
Hooks do not fire for `wp_ai_client_prompt()` flows. They do fire for
`AiClient::prompt()` (or any `PromptBuilder` constructed with the third
argument).
**Steps to reproduce**
- Use WordPress 7.0+ trunk/beta with AI connectors configured so a simple
text generation succeeds.
- In a small mu-plugin or wp shell:
{{{#!php
<?php
add_action( 'wp_ai_client_before_generate_result', static function () {
error_log( 'before_generate FIRED' );
}, 10, 1 );
add_action( 'wp_ai_client_after_generate_result', static function () {
error_log( 'after_generate FIRED' );
}, 10, 1 );
$result = wp_ai_client_prompt( 'Say hello in one word.'
)->generate_text_result();
// Optional: inspect $result; generation may succeed while hooks never
ran.
}}}
- Check WP_DEBUG_LOG (or equivalent): no log lines appear.
- For comparison, temporarily use:
{{{#!php
<?php
$result = \WordPress\AiClient\AiClient::prompt( 'Say hello in one word.'
)->generateTextResult();
}}}
- Observe before/after log lines do appear (same dispatcher, correct
PromptBuilder wiring).
**Proposed fix (minimal)**
In `WP_AI_Client_Prompt_Builder::__construct()`:
{{{#!php
<?php
// Pass the dispatcher into the SDK builder, e.g.
new PromptBuilder( $registry, $prompt, AiClient::getEventDispatcher() )
// and in the catch branch
new PromptBuilder( $registry, null, AiClient::getEventDispatcher() )
}}}
This aligns the WordPress wrapper with AiClient::prompt() and with core’s
existing setEventDispatcher() bootstrap.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64935>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list