Skip to content

Add support for streaming response bodies #1056

Description

@thelovekesh

Is your feature request related to a problem?

As part of the ongoing AI work, we want core to stream AI responses so tokens can be shown as they arrive, instead of waiting for the whole response to finish. We cannot do this today because Requests offers no readable response body you can pull from incrementally. By default it accumulates the entire body in memory before returning (cURL, fsockopen). The only ways to touch bytes mid-transfer are push-only and run entirely inside the blocking request call: the request.progress hook (which still buffers the whole body and cannot abort), and writing to a handle through filename (write-only, no readable stream). Neither yields a stream the AI SDK can pull from.

This blocks the AI client SDK. Its streaming support (WordPress/php-ai-client#255) reads the response body as a stream and pulls from it as data arrives, so it needs an HTTP client that can return a body that is read incrementally. WordPress cannot provide one today, because the HTTP client underneath buffers the response and only returns it once it is complete.

Describe the solution you'd like

Add an opt-in way to read a response body incrementally as it arrives, without holding the whole body in memory.

The shape the SDK needs is a body that can be pulled from while the response is still streaming, so a PSR-18 adapter over WP_Http can expose it as a readable stream. Rough shape:

$response = Requests::request($url, $headers, $data, $type, ['stream' => true]);
while (!$response->eof()) {
    $chunk = $response->read(8192); // returns data as it arrives off the connection
    // handle each chunk
}

When streaming is not requested, nothing changes and behavior stays exactly as it is today. This gives core the primitive it needs to extend WP_Http and let the AI client stream on WordPress.

Describe alternatives you've considered

  • The existing request.progress hook, which both transports dispatch (cURL, fsockopen), and which WordPress re-emits as the requests-request.progress action. It can observe chunks today, but it cannot back a real streaming feature: the full body is still buffered and returned regardless, the transfer cannot be stopped from it, it is a global action with no per-request context so a caller cannot tell which request a chunk belongs to, and it is only clean on cURL. It also cannot feed the SDK, which pulls from a readable body rather than receiving pushed chunks.
  • Writing to a custom stream wrapper or php://output through filename. This does deliver chunks without buffering, but it is a write-only sink with no readable stream to pull from, and it runs entirely inside the blocking call. WP_Http also rejects targets like these, since it requires the stream destination to be a writable directory. So it cannot give the SDK a readable body either.
  • A pull-based readable body is a larger change than a push callback, since it needs the transport to read in steps rather than in one blocking call. The callback is smaller, but it does not satisfy the SDK's pull model on its own, which is why the readable body is the primary ask.

Additional context (optional)

  • AI SDK streaming PR: Add support for streaming php-ai-client#255

  • The SDK reads the body as a PSR-7 stream and pulls until the end of the stream, so it needs a body that can be read incrementally, not one pushed through a hook.

  • I intend to create a pull request to implement this feature myself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions