Skip to content

Conversation

@JasonTheAdams
Copy link
Member

@JasonTheAdams JasonTheAdams commented Oct 15, 2025

Resolves #99

This updates the HTTP stack so we can pass request-specific transport options end to end. We now have a nullable RequestOptions DTO that threads through Request, ModelConfig, and the transporter contracts, so the HttpTransporter understands both our option-aware clients and Guzzle-style clients that expose a send($request, $options) signature. The change also touches supporting enums/mocks and adds unit coverage to lock in the new behaviour.

Alongside that, the new ClientWithOptionsInterface offers a lightweight extension point for PSR-18 clients that already know how to accept option bags. Libraries that wrap Guzzle or provide their own richer transport (like our WP AI Client repo) can implement this interface to let the transporter hand them a RequestOptions instance directly, avoiding reflection while keeping the core client agnostic.

@github-actions
Copy link

github-actions bot commented Oct 15, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: JasonTheAdams <jason_the_adams@git.wordpress.org>
Co-authored-by: felixarntz <flixos90@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@JasonTheAdams JasonTheAdams self-assigned this Oct 15, 2025
@JasonTheAdams
Copy link
Member Author

This is ready for you, @felixarntz!

One thing I went back and forth on: Are DTOs supposed to be immutable? At first I thought yes, but only because I thought I remembered it, but then I realized that ModelConfig has setters. Thinking they're immutable is why I used withX immutable methods in RequestOptions. If that's not the case I'll switch it to setters to keep things simple.

@felixarntz
Copy link
Member

felixarntz commented Oct 15, 2025

One thing I went back and forth on: Are DTOs supposed to be immutable? At first I thought yes, but only because I thought I remembered it, but then I realized that ModelConfig has setters. Thinking they're immutable is why I used withX immutable methods in RequestOptions. If that's not the case I'll switch it to setters to keep things simple.

Yes, I think they generally should be. The ModelConfig only has setters because we didn't want to use a giant $args array for the constructor, but that's still a less than ideal workaround - ideally it should be immutable too. I think for now we should model RequestOptions like ModelConfig, just to be able to proceed quickly. But we should assume it's supposed to be immutable, still. We can discuss in a separate issue how we want to make these two classes technically immutable (which are only different from the others because they support so many potential keys).

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 Overall this looks great!

A few points of feedback and a few questions that I think need to be addressed, but it's near-perfect, pending a few simplifications.

Note that there was already a PR for this in #105, so we'll need to see how we want to proceed.

* @param ClientInterface $client The HTTP client instance.
* @return bool True when the client exposes Guzzle's send signature.
*/
private function isGuzzleClient(ClientInterface $client): bool
Copy link
Member

Choose a reason for hiding this comment

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

Love this! It's a really creative and pragmatic solution which, while hacky, is exactly what we need to make for a good DX for most, without forcing Guzzle on everyone. 🙌

And with these methods being private, there's no risk. If we think this is bad later, we could simply remove it.

@felixarntz felixarntz added the [Type] Enhancement A suggestion for improvement. label Oct 15, 2025
@felixarntz felixarntz added this to the 0.2.0 milestone Oct 15, 2025
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 Looks great - only minor notes now, nothing blocking.

Comment on lines +31 to +39
/**
* @var float|null Maximum duration in seconds to wait for the full response.
*/
protected ?float $timeout = null;

/**
* @var float|null Maximum duration in seconds to wait for the initial connection.
*/
protected ?float $connectTimeout = null;
Copy link
Member

Choose a reason for hiding this comment

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

Are these values usually handled as float? I totally see why that could be reasonable, but at the same I don't recall ever seeing a non-integer timeout value anywhere. Given we're not talking about very small durations for either of these, maybe it seems a bit excessive to support "I want to wait 5.5 seconds".

Curious what you think.

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's a float in WP_Http::request(), so I see no reason to limit it. If someone needs that level of precision, then power to them. Hahah! If the subsequent system only supports ints, then it can truncate it without much concern.

@JasonTheAdams JasonTheAdams merged commit 6c39723 into trunk Oct 17, 2025
7 checks passed
@JasonTheAdams JasonTheAdams deleted the http-request-options branch October 17, 2025 01:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support defining request options

3 participants