Skip to content

Conversation

@JasonTheAdams
Copy link
Member

@JasonTheAdams JasonTheAdams commented Oct 21, 2025

This introduces a WP-standards compatible version of the PHP AI Client's PromptBuilder, now the Prompt_Builder.

It also introduces an experimental Prompt_Builder_With_WP_Error that returns WP_Error when possible instead of throwing exceptions. I'm tempted to only do this for terminating functions. Doing this for fluent methods such as using_model_preference() breaks method changing, as we can't be sure $this was returned.

Remaining work:

  • Add support for Abilities API (turning an Ability into a function declaration)
  • Add some hooks (may require changes to PHP AI Client)

@JasonTheAdams JasonTheAdams mentioned this pull request Oct 21, 2025
6 tasks
Copy link
Member

@felixarntz felixarntz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonTheAdams A few high-level comments on the implementation, where I think we can simplify things.

parent::usingModelPreference( ...$preferred_models );
return $this;
} catch ( InvalidArgumentException $e ) {
return new \WP_Error(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this contradicts your point of only returning WP_Error for the terminate methods?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does indeed! Hahah! I left this year to illustrate the point that it breaks the fluent method. It sounds like you're in agreement that we shouldn't throw WP_Error in the fluent methods?

* @method File generate_speech() Generates speech from the prompt.
* @method list<File> generate_speeches(?int $candidateCount = null) Generates multiple speech outputs from the prompt.
*/
class Prompt_Builder extends PromptBuilder {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not extend PromptBuilder, but use a decorator pattern. That makes a lot more sense for this purpose.

We're creating an alternative implementation, not a child implementation. For instance, it's very confusing to have both generateText and generate_text as methods.

In other words, let's have these two classes be independent, and instead create a new PromptBuilder internally in the Prompt_Builder constructor.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you and want more thoughts. I extended because a while back we talked about adding hooks into this, such as filtering the returned model. By extending we could overload certain methods.

If we don't do that it's harder to do that in the Decorator pattern. Maybe you have a clever idea? One option would be to add methods in the PHP AI Client that accepts a callable? Something like filteringReturnedModels(callable $callback)? It then stores that and calls it at the appropriate moment(s)?

What do you think, @felixarntz?

*
* @return GenerativeAiResult|\WP_Error The generated result, or WP_Error on failure.
*/
public function generate_result( ?CapabilityEnum $capability = null ) {
Copy link
Member

@felixarntz felixarntz Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holistically, I think we can take a simpler approach instead of overriding all terminate methods:

  • In this class, override __call from the regular WP based Prompt_Builder.
  • In the override, wrap the parent method call in a try catch.
  • In the catch, turn any exception into a WP_Error.
  • Then we can use a method name based allowlist to check whether the current call is for a terminate method.
  • If yes, we return the WP_Error immediately.
  • If not, we store the WP_Error in the class property to return later, whenever the terminate method is called.
  • Additionally, before the try catch, we include a check for whether a WP_Error is already set in the class property. If so, we simply return $this immediately before doing anything else. Or, if the current method is a terminate method, we can return the WP_Error from the class property at that point.

This implementation is a lot more straightforward and more robust than having to do it for every individual method. It also holistically takes into account any exception that may be thrown anywhere, including before the terminate methods.

I think the only exception that we should still keep throwing would be for an invalid method name, as that's clearly an implementation flaw that is similar to calling an undefined method or function, which even in the WordPress way will normally (and should) result in an exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants