diff --git a/inc/Engine/AI/RequestBuilder.php b/inc/Engine/AI/RequestBuilder.php index c0561e70..4bd36585 100644 --- a/inc/Engine/AI/RequestBuilder.php +++ b/inc/Engine/AI/RequestBuilder.php @@ -137,7 +137,11 @@ public static function build( $timeout_filter = static function ( $default_timeout ) use ( $request_timeout ) { return max( (float) $default_timeout, $request_timeout ); }; - $curl_filter = static function ( $handle ) use ( $request_timeout ) { + $curl_filter = static function ( $handle ) use ( $request_timeout, $connect_timeout ) { + if ( defined( 'CURLOPT_CONNECTTIMEOUT' ) ) { + curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, (int) ceil( $connect_timeout ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt -- WordPress exposes the cURL handle only through this hook. + } + if ( defined( 'CURLOPT_LOW_SPEED_TIME' ) ) { curl_setopt( $handle, CURLOPT_LOW_SPEED_TIME, (int) ceil( $request_timeout ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt -- WordPress exposes the cURL handle only through this hook. } diff --git a/tests/wp-ai-client-request-timeout-smoke.php b/tests/wp-ai-client-request-timeout-smoke.php index 5ba26cf0..5d3468c0 100644 --- a/tests/wp-ai-client-request-timeout-smoke.php +++ b/tests/wp-ai-client-request-timeout-smoke.php @@ -278,6 +278,10 @@ function ( float $timeout, string $mode, string $provider, string $model, array assert_timeout_smoke( 'continue' === $captured_prompt, 'Data Machine passes latest user message as wp-ai-client prompt' ); assert_timeout_smoke( 1 === ( TimeoutPromptBuilderDouble::$captured_request['curl_filter_count'] ?? null ), 'Data Machine scopes cURL low-speed settings during wp-ai-client dispatch' ); +$request_builder_source = file_get_contents( __DIR__ . '/../inc/Engine/AI/RequestBuilder.php' ); +assert_timeout_smoke( is_string( $request_builder_source ) && str_contains( $request_builder_source, 'CURLOPT_CONNECTTIMEOUT' ), 'Data Machine scopes cURL connect timeout during wp-ai-client dispatch' ); +assert_timeout_smoke( is_string( $request_builder_source ) && str_contains( $request_builder_source, 'use ( $request_timeout, $connect_timeout )' ), 'Data Machine cURL timeout hook receives request and connect timeouts' ); + assert_timeout_smoke( 0 === timeout_smoke_filter_count( 'wp_ai_client_default_request_timeout' ), 'Data Machine removes temporary wp-ai-client timeout filter after dispatch' ); assert_timeout_smoke( 0 === timeout_smoke_filter_count( 'http_api_curl' ), 'Data Machine removes temporary cURL low-speed filter after dispatch' );