Make WordPress Core

Opened 4 weeks ago

Closed 3 weeks ago

#65094 closed defect (bug) (fixed)

AI: Prompt construction fails with fatal error when wp_ai_client_default_request_timeout filter returns negative number

Reported by: westonruter's profile westonruter Owned by: westonruter's profile westonruter
Milestone: 7.0 Priority: normal
Severity: normal Version:
Component: AI Keywords: has-patch has-unit-tests commit dev-reviewed
Focuses: Cc:

Description

Consider this code:

add_filter(
	'wp_ai_client_default_request_timeout',
	static function () {
		return -1;
	}
);

This causes a fatal error to occur when constructing a prompt with wp_ai_client_prompt():

WordPress\AiClient\Common\Exception\InvalidArgumentException: Request option "timeout" must be greater than or equal to 0.

/var/www/src/wp-includes/php-ai-client/src/Providers/Http/DTO/RequestOptions.php:201
/var/www/src/wp-includes/php-ai-client/src/Providers/Http/DTO/RequestOptions.php:52
/var/www/src/wp-includes/php-ai-client/src/Providers/Http/DTO/RequestOptions.php:169
/var/www/src/wp-includes/ai-client/class-wp-ai-client-prompt-builder.php:203
/var/www/src/wp-includes/ai-client.php:59

As exceptions are caught in ability callbacks (#65058) and generally WP_Error objects are returned, it would seem this exception should be caught in favor of issuing _doing_it_wrong().

Note: I stumbled upon this issue when looking at the AI codebase in PHPStan with rule level 10 applied. For this line:

<?php
$default_timeout = (int) apply_filters( 'wp_ai_client_default_request_timeout', 30 );

PHPStan complains with:

Cannot cast mixed to int.

I started adding an is_numeric() check here and this led me down to looking at the validation logic in \WordPress\AiClient\Providers\Http\DTO\RequestOptions::validateTimeout().

Change History (32)

This ticket was mentioned in PR #11596 on WordPress/wordpress-develop by @westonruter.


4 weeks ago
#1

  • Keywords has-patch has-unit-tests added

Trac ticket: https://core.trac.wordpress.org/ticket/65094

The primary change here is in WP_AI_Client_Prompt_Builder::__construct() to check that the return value of the wp_ai_client_default_request_timeout filter is in fact a non-negative float. It also newly allows the value null. Otherwise, the filtered value is discarded in favor of using the original default of 30, and a _doing_it_wrong() is issued. Without this check, a fatal error would ensue due to an exception being thrown by \WordPress\AiClient\Providers\Http\DTO\RequestOptions::validateTimeout().

In addition to this change, static analysis issues were resolved:

  • Use float instead of int for the wp_ai_client_default_request_timeout.
  • Adding missing PHP imports for Message and MessagePart for the PHPDoc for wp_ai_client_prompt().
  • Adding PHP type hints for the return values of wp_ai_client_prompt() and \WP_AI_Client_Cache::getMultiple().
  • Use native property type hints in WP_AI_Client_HTTP_Client.

The following PHPStan level 10 issues are resolved:

  1. src/wp-includes/ai-client.php: Parameter $prompt of function wp_ai_client_prompt() has invalid type Message.
  2. src/wp-includes/ai-client.php: Parameter $prompt of function wp_ai_client_prompt() has invalid type MessagePart.
  3. src/wp-includes/ai-client/class-wp-ai-client-prompt-builder.php: Cannot cast mixed to int.

## Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Optus 4.7
Used for: Research

#2 @darshitrajyaguru97
4 weeks ago

Patch Testing & Review

I tested the latest patch locally and reviewed the changes in detail.

Environment

  • WordPress: 7.0 RC2
  • PHP: 8.3.x
  • Server: Nginx
  • Browser: Chrome
  • OS: Windows

Summary

The patch successfully prevents a fatal error when invalid values are returned via the
wp_ai_client_default_request_timeout filter.

Previously, returning a negative value or invalid type would propagate into
RequestOptions::validateTimeout() and throw an uncaught exception, resulting in a fatal error.
With this patch, the value is validated earlier and handled gracefully.

Testing Performed

I tested multiple scenarios:

  • Returning -1 → Falls back to default 30.0_doing_it_wrong() triggered → No fatal error ✅
  • Returning 45.5 → Value applied correctly ✅
  • Returning null → Timeout disabled (null) as expected ✅
  • Returning invalid type (e.g., array) → Falls back to default → _doing_it_wrong() triggered ✅

All cases behaved as expected and no regressions were observed.

Code Review Notes

  • Validation logic in WP_AI_Client_Prompt_Builder::__construct() is solid:
    • Accepts non-negative numeric values
    • Explicitly supports null
    • Safely falls back for invalid input
  • Use of _doing_it_wrong() aligns well with WordPress core practices and avoids hard failures inside filters
  • Switching to float improves flexibility and resolves PHPStan level 10 issues
  • Additional improvements:
    • Proper return type declarations
    • Missing imports added
    • Native property typing applied

Unit Tests

New PHPUnit tests provide good coverage:

  • Valid float override
  • null handling
  • Negative value rejection
  • Invalid type rejection

All tests pass locally.

Feedback

This is a well-rounded fix that:

  • Improves resilience of the AI client
  • Prevents fatal errors in edge cases
  • Enhances developer experience with clear feedback

The approach is consistent with core standards.

Conclusion

Patch tested successfully — works as expected.
No issues found during testing in this environment; needs to be tested across different environments as well for better clarity.

#3 @adrmf25
4 weeks ago

Tested this issue in a local WordPress development environment.

Steps:

  • Set up local WordPress Core
  • Applied the wp_ai_client_default_request_timeout filter
  • Initially placed it in wp-config.php, which caused a fatal error (add_filter not available at that stage)
  • Moved the filter to functions.php, where WordPress is fully loaded

Result:

  • No fatal errors when applied correctly
  • WordPress runs normally

Conclusion:
The behavior works as expected when the filter is used in the proper context.

#4 @jarodortegaaraya
4 weeks ago

Patch Testing Report – Ticket #65094

I tested the patch locally in a WordPress 7.0 environment.

Summary:
The patch successfully prevents a fatal error when invalid values are returned via the wp_ai_client_default_request_timeout filter. Previously, invalid values (e.g., -1) caused an uncaught exception in RequestOptions::validateTimeout().

Testing Performed:

Returning -1 → Falls back to default (30) → No fatal error ✅
Returning 45.5 → Value applied correctly ✅
Returning null → Timeout disabled as expected ✅
Returning invalid type (array) → Falls back to default → No fatal error ✅

Additional Observation:
A PHP warning was encountered during testing due to an undefined variable ($default_timeout) after applying the patch manually. This appears to be related to the local modification rather than the intended patch behavior.

Conclusion:
The patch works as expected. It properly validates the timeout value, prevents fatal errors, and handles invalid input gracefully.

#5 @khushdoms
4 weeks ago

Tested the patch locally in a WordPress 7.0 development environment.

Testing setup:

  • Theme: Twenty Twenty-Five (v1.4)
  • Added the following filter and test trigger in functions.php:

`
add_filter(

'wp_ai_client_default_request_timeout',
function () {

return -1;

}

);

add_action('init', function () {

if ( function_exists('wp_ai_client_prompt') ) {

wp_ai_client_prompt("Test prompt");

}

});
`

Before applying the patch:

  • Encountered a fatal error: InvalidArgumentException: Request option "timeout" must be greater than or equal to 0

screenshot : https://prnt.sc/yC5V3AwWnwyF

After applying the patch:

  • No fatal error occurs ✅
  • Invalid timeout value is handled gracefully
  • Application continues to run normally

The patch successfully prevents the fatal error and aligns with expected WordPress error-handling practices.

Patch works as expected 👍

@westonruter commented on PR #11596:


4 weeks ago
#6

@justlevine:

what benefit does changing wp_ai_client_default_request_timeout to support ?float instead of _just_ float?

I suppose because this matches the types supported by RequestOptions. Also, doing strict equality checks between float values is not safe. For example: https://3v4l.org/QYUem

So I don't think it is completely reliable to use 0.0 as the value for disabling the timeout. Better to use null to match RequestOptions.

@justlevine commented on PR #11596:


4 weeks ago
#7

@justlevine:

what benefit does changing wp_ai_client_default_request_timeout to support ?float instead of _just_ float?

I suppose because this matches the types supported by RequestOptions. Also, doing strict equality checks between float values is not safe. For example: https://3v4l.org/QYUem

So I don't think it is completely reliable to use 0.0 as the value for disabling the timeout. Better to use null to match RequestOptions.

@westonruter Not sure I follow your reliability concerns: https://3v4l.org/vk3Pc . But worst case we can coerce to whatever "stable" check you feel comfortable with: $default_timeout = (int) $default_timeout === 0 ? ... or ! empty( $timeout ) ? ... or whatever all seem a lot more easy to reason with then multiple conditional paths.

As far as matching RequestOptions, personally I don't see a need or justification for an internal hook to match the shape of a DTO, if our internal implementation needs the whole shape.

However, if folks feel a need to align the two, then I'd suggest making the type on the DTO stricter, not loosening our _public_ API (the hook signature) to accommodate the unnecessary polymorphism and edge cases.

@westonruter commented on PR #11596:


4 weeks ago
#8

Not sure I follow your reliability concerns: https://3v4l.org/vk3Pc . But worst case we can coerce to whatever "stable" check you feel comfortable with: $default_timeout = (int) $default_timeout === 0 ? ... or ! empty( $timeout ) ? ... or whatever all feel easier to reason with than multiple conditional paths.

It's not reliable to check if a float value is equal to 0.0, especially if arithmetic has been done on the value. Since the value has come from a filter, we do not know what operations have been done on it.

Casting the value to int is not viable either because it will prevent values like 0.5 from being usable.

@justlevine commented on PR #11596:


4 weeks ago
#9

Not sure I follow your reliability concerns: https://3v4l.org/vk3Pc . But worst case we can coerce to whatever "stable" check you feel comfortable with: $default_timeout = (int) $default_timeout === 0 ? ... or ! empty( $timeout ) ? ... or whatever all feel easier to reason with than multiple conditional paths.

It's not reliable to check if a float value is equal to 0.0, especially if arithmetic has been done on the value. Since the value has come from a filter, we do not know what operations have been done on it.

Casting the value to int is not viable either because it will prevent values like 0.5 from being usable.

what arethmeric though? we're casting it on our side and in full control of the value. And yeah casting locally to int _just for a falsely check_ wouldn't prevent 0.5 at all...

@westonruter commented on PR #11596:


4 weeks ago
#10

what arithmetic though? we're casting it on our side _after_ the filter, and we in full control of the value and what happens to it afterwards. And yeah casting locally to int _just for a falsely check_ wouldn't prevent 0.5 at all... #11596 (comment)

For example:

add_filter( 'wp_ai_client_default_request_timeout', function ( $value ) {
    return $value - (float) get_option( 'my_timeout_delta' );
} );

The value being passed in is a float to begin with here. So the casting being added here is just in case there is a string value in one of the filter callbacks.

@westonruter commented on PR #11596:


4 weeks ago
#11

Something else to consider is the fact that float values can be infinity (INF). That would effectively be the same as null. In that case, should \WordPress\AI_Client\HTTP\WordPress_HTTP_Client::prepare_wp_args() be updated to account for that?

  • src/wp-includes/ai-client/adapters/class-wp-ai-client-http-client.php

    a b class WP_AI_Client_HTTP_Client implements ClientInterface, ClientWithOptionsInte 
    138138                );
    139139
    140140                if ( null !== $options ) {
    141                         if ( null !== $options->getTimeout() ) {
     141                        if ( null !== $options->getTimeout() && is_finite( $options->getTimeout() ) ) {
    142142                                $args['timeout'] = $options->getTimeout();
    143143                        }

While the timeout arg for WP HTTP says it takes a float, it's not clear that INF would be allowed.

Oh, something more important I'm seeing as well: currently when null is passed, this is preventing prepare_wp_args() from setting the timeout, which is causing the _default_ timeout of 5 to be used when the request is actually set. This doesn't seem entirely expected. If null (or INF) is supplied, then it would seem that _something_ should be set to the default value from being used.

@justlevine commented on PR #11596:


4 weeks ago
#12

what arithmetic though? we're casting it on our side _after_ the filter, and we in full control of the value and what happens to it afterwards. And yeah casting locally to int _just for a falsely check_ wouldn't prevent 0.5 at all... #11596 (comment)

For example:

I feel like that example bolsters _my_ point? Adding a line:

+ add_filter( 'wp_ai_client_default_request_timeout', '__return_null' ); // somewhere else
add_filter( 'wp_ai_client_default_request_timeout', function ( $value ) {
    return $value - (float) get_option( 'my_timeout_delta' );
} );

since $value is assumed a float, if someone forgets to cast it from null like in your example it won't be an issue. Meanwhile the return (float) apply_filters() means that even if they return an int or null or empty string, we can pass to to our dto... e.g. add_filter('wp_ai_client_default_request_timeout', '__return_false' ); where itl be caught by PHPStan but only error if a filter like yours conflicts.

Perhaps you can add a test that would red if someone refactors this in the future to cast the results of apply_filters(), but pass because we're doing it with null|float and explicit checking? Would prevent the regression you're clearly concerned about, and be a easier for me to follow concretely.

If null (or INF) is supplied, then it would seem that something should be set to the default value from being used.

(Putting aside that the null issue is solved by not allowing it/casting to float), remember this whole thing is just a shallow wrapper for WordPress/requests. If that library is missing handling for one of these edge cases, then IMO the behavior should be handled _there_, not absorbed downstream in our (or any other component). even without the type safety these aren't particularly common foot guns I don't think.

@westonruter commented on PR #11596:


4 weeks ago
#13

since $value is assumed a float, if someone forgets to cast it from null like in your example it won't be an issue. Meanwhile the return (float) apply_filters() means that even if they return an int or null or empty string, we can pass to to our dto... e.g. add_filter('wp_ai_client_default_request_timeout', '__return_false' ); where itl be caught by PHPStan but only error if a filter like yours conflicts.

I'm just trying to say that the return value if an applied filter will be a float and we can't reliably compare it with 0.0 because of floating point math.

Because RequestOptions::validateTimeout() allows a float or null, where null apparently is supposed to mean that there is no timeout enforced (but maybe I'm wrong). It seems there should be an ability to disable a timeout, such as in a WP-CLI context. Returning null would make sense as the way to disable the timeout given what is allowed by RequestOptions. Otherwise, if we don't want to allow null, we could document INF as a valid value. But we can't use 0.0 because testing equality with floats is not reliable.

@justlevine commented on PR #11596:


4 weeks ago
#14

Because RequestOptions::validateTimeout() allows a float or null, where null apparently is supposed to mean that there is no timeout enforced (but maybe I'm wrong).

If I'm not mistaken and as you also noted, wp_safe_remote_request() / WordPress/Requests treats 0 (or 0.0 ) as no timeout, whereas null falls back to the default fallback of _5s_ and not our 30s that we use for the hook here. The dto as _implemented_ follows that, so IMO it make sense to lock down the dto not to change the meaning of null to use it in our hook.

I still don't understand the point youre trying to make about float-math. There's never a time wed need to do a float === float check, literally any falsey value can be coerced to the 0 or 0.0 that we to send the DTO, and unless you're saying you want it to be positive-float|0 (which imo is still an improvement over *|null), I'm lost as to what edge case this protects against. So with that I'm going to respectfully tap out (unless a test case gets added that covers it) 🙇‍♂️

@justlevine commented on PR #11596:


4 weeks ago
#15

( fwiw http_request_timeout is also typed as a float https://github.com/WordPress/wordpress-develop/blob/074792ef21d9160a8fabdda215f8bf48f7a91d43/src/wp-includes/class-wp-http.php#L178-L181, but consistency for its own sake isn't an argument, if it's deserving we can just as easily broaden the type there too. )

@westonruter commented on PR #11596:


4 weeks ago
#16

There's never a time wed need to do a float === float check

This is what you suggested in https://github.com/WordPress/wordpress-develop/pull/11596#discussion_r3111408318.

@justlevine commented on PR #11596:


4 weeks ago
#17

There's never a time wed need to do a float === float check

This is what you suggested in #11596 (comment).

yes and as the comment there and the rest of our conversation indicate, that was me attempting to understanding your concern, but IMO even this is unnecessary and we can just let folks pass any float value they want and not do any coercing beyond the negative-int check in the dto. 🤷‍♂️

@westonruter commented on PR #11596:


4 weeks ago
#18

If I'm not mistaken and as you also noted, wp_safe_remote_request() / WordPress/Requests treats 0 (or 0.0 ) as no timeout

I don't think I suggested this. A timeout of zero actually gets increased to 1 second:

https://github.com/WordPress/wordpress-develop/blob/047ef806c329a11ba6357f1a650f04f3703e3a44/src/wp-includes/Requests/src/Transport/Curl.php#L425-L431

I tested this by creating a file called sleep-2.php locally:

<?php
sleep( 2 );
echo "Awake!";

Then, from that directory I started a server:

php -S 0.0.0.0:8888

Then in the wordpress-develop environment, I put this file:

<?php
$response = wp_remote_get(
        'http://host.docker.internal:8888/sleep-2.php  ',
        array( 'timeout' => 0.0 )
);

if ( is_wp_error( $response ) ) {
        WP_CLI::error( $response->get_error_message() );
}

WP_CLI::log( 'Code: ' . wp_remote_retrieve_response_code( $response ) );
WP_CLI::log( 'Body: ' . wp_remote_retrieve_body( $response ) );

And when I do this:

npm run env:cli eval-file -- try-timeout.php

I get this:

Error: cURL error 28: Operation timed out after 1004 milliseconds with 0 bytes received

So a timeout of 0.0 does _not_ mean the timeout is disabled in WordPress HTTP API.

If I change the timeout to 3.0, then I get this:

Code: 200
Body: Awake!

Note that if I use INF here:

$response = wp_remote_get(
        'http://host.docker.internal:8888/sleep-2.php  ',
        array( 'timeout' => INF )
);

Then this also does not time-out, so it seems to be valid at least for the cURL transport.

So we cannot use a value of 0.0 to indicate the timeout is disabled. Either we have the filter return null, INF, or just have the user return a super big number. To override the WP HTTP API's 5 second default timeout, we'll need to provide _something_, regardless of the return value from wp_ai_client_default_request_timeout. Either INF or a super big number seem to work, so if null is returned we'll need to map to either of those values.

#19 @tusharaddweb
4 weeks ago

Tested the issue and confirm that return a negative value for the wp_ai_client_default_request_timeout filter generate a fatal error during prompt construction.

The patch correctly handle invalid timeout values and prevents the crash. AI requests now work as expected.

#20 @khushdoms
4 weeks ago

Additionally tested with:

  • null return → works as expected
  • float values → handled correctly

No regressions observed.

#21 @gaurangsondagar
4 weeks ago

Patch Testing Report

Patch Tested: https://core.trac.wordpress.org/ticket/65094

Environment:

  • WordPress: 7.0 RC2
  • PHP: 8.2.x
  • Server: Apache
  • Browser: Chrome
  • OS: Ubuntu

Test Summary:

  • Set up the WordPress Core 7.0 RC2 locally
  • Applied the wp_ai_client_default_request_timeout filter in the theme's functions.php and tested the possible cases.

Result:
The patch is working as expected. It has been validated successfully and does not produce any fatal errors when applied correctly.

This ticket was mentioned in Slack in #core by audrasjb. View the logs.


3 weeks ago

#23 @audrasjb
3 weeks ago

As per today's bug scrub: The PR was successfully tested several times and approved by @justlevine. I think we're getting close to a resolution. @westonruter do you need more testing on this?

#24 @westonruter
3 weeks ago

  • Keywords commit added

I'll commit this today.

#25 @westonruter
3 weeks ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 62255:

AI: Validate filtered default request timeout in WP_AI_Client_Prompt_Builder.

This checks that the return value of the wp_ai_client_default_request_timeout filter is a non-negative number before passing it to RequestOptions. If the filtered value is invalid, it is discarded in favor of the original default of 30.0 and a _doing_it_wrong() notice is issued. Without this check, a fatal error would ensue from the exception thrown in \WordPress\AiClient\Providers\Http\DTO\RequestOptions::validateTimeout().

The following static analysis issues are addressed:

  • Use float instead of int for the wp_ai_client_default_request_timeout filter parameter.
  • Add missing PHP imports for Message and MessagePart in the PHPDoc for wp_ai_client_prompt().
  • Add PHP return type hints for wp_ai_client_prompt() and WP_AI_Client_Cache::getMultiple().
  • Use native property type hints in WP_AI_Client_HTTP_Client.

Developed in https://github.com/WordPress/wordpress-develop/pull/11596

Props westonruter, justlevine, flixos90, khushdoms, darshitrajyaguru97, adrmf25, jarodortegaaraya, tusharaddweb, gaurangsondagar.
Fixes #65094.

#26 @westonruter
3 weeks ago

  • Keywords dev-feedback added
  • Resolution fixed deleted
  • Status changed from closed to reopened

Re-opening for merging into 7.0 branch after sign-off.

#27 @khushdoms
3 weeks ago

Performed additional edge-case testing on 7.0 RC2:

  • null → handled safely, no fatal error
  • INF → no crash, request proceeds as expected
  • float (0.5) → accepted and applied correctly
  • invalid string → ignored, fallback applied
  • large value → works without issues

No regressions observed across all cases.

The fix is robust and handles unexpected filter inputs gracefully.

Suggestion:
It may be helpful to document supported return types for this filter (float, null, INF) to improve developer clarity.

#28 @dhrumilk
3 weeks ago

Steps performed:

  • Set up a fresh local WordPress core environment
  • Attempted to apply the wp_ai_client_default_request_timeout filter
  • Initially added the filter in wp-config.php, which resulted in a fatal error since add_filter() is not available at that early stage of execution
  • Relocated the filter to functions.php, where WordPress is fully loaded and hooks are accessible

Result:

  • No fatal errors occurred when the filter was implemented in the correct location
  • WordPress functioned as expected without any issues

Conclusion:
The behavior is correct and expected. The filter works properly when used within the appropriate context (i.e., after WordPress has fully initialized), and the earlier error was due to placing it too early in the load sequence.

Last edited 3 weeks ago by dhrumilk (previous) (diff)

#29 @priyankaadbrains
3 weeks ago

I tested the issue and confirmed that returning a negative value for the ⁠ wp_ai_client_default_request_timeout ⁠ filter causes a fatal error during prompt construction.

The patch properly handles invalid timeout values and prevents the crash. AI requests are now functioning as expected.

#30 @westonruter
3 weeks ago

Here's a quick way to test this.

Add a this as a try-wp-ai-client-negative-default-request-timeout.php file to the root of a WP install:

<?php

add_filter(
        'wp_ai_client_default_request_timeout',
        static function () {
                return -1;
        }
);

echo wp_ai_client_prompt( 'When is Christmas?' )->generate_text();

Then invoke with WP-CLI:

npm run env:cli -- eval-file try-wp-ai-client-negative-default-request-timeout.php

Before:

Fatal error: Uncaught WordPress\AiClient\Common\Exception\InvalidArgumentException: Request option "timeout" must be greater than or equal to 0. in /var/www/src/wp-includes/php-ai-client/src/Providers/Http/DTO/RequestOptions.php:201

After:

Notice: Function WP_AI_Client_Prompt_Builder::__construct was called incorrectly. The wp_ai_client_default_request_timeout filter must return a non-negative number. Please see Debugging in WordPress for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6173
Christmas is celebrated on December 25th each year.

#31 @peterwilsoncc
3 weeks ago

  • Keywords dev-reviewed added; dev-feedback removed

r62255 approved for merge to the 7.0 branch.

Last edited 3 weeks ago by peterwilsoncc (previous) (diff)

#32 @peterwilsoncc
3 weeks ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 62266:

AI: Validate filtered default request timeout in WP_AI_Client_Prompt_Builder.

This checks that the return value of the wp_ai_client_default_request_timeout filter is a non-negative number before passing it to RequestOptions. If the filtered value is invalid, it is discarded in favor of the original default of 30.0 and a _doing_it_wrong() notice is issued. Without this check, a fatal error would ensue from the exception thrown in \WordPress\AiClient\Providers\Http\DTO\RequestOptions::validateTimeout().

The following static analysis issues are addressed:

  • Use float instead of int for the wp_ai_client_default_request_timeout filter parameter.
  • Add missing PHP imports for Message and MessagePart in the PHPDoc for wp_ai_client_prompt().
  • Add PHP return type hints for wp_ai_client_prompt() and WP_AI_Client_Cache::getMultiple().
  • Use native property type hints in WP_AI_Client_HTTP_Client.

Developed in https://github.com/WordPress/wordpress-develop/pull/11596

Reviewed by peterwilsoncc.
Merges r62255 to the 7.0 branch.

Props westonruter, justlevine, flixos90, khushdoms, darshitrajyaguru97, adrmf25, jarodortegaaraya, tusharaddweb, gaurangsondagar.
Fixes #65094.

Note: See TracTickets for help on using tickets.