From dd73ab030a063e7364b6f382c5d7f3b385011a84 Mon Sep 17 00:00:00 2001 From: Jason Adams Date: Wed, 26 Nov 2025 12:58:19 -0700 Subject: [PATCH 1/4] feat: adds ability to set model request options --- src/Builders/PromptBuilder.php | 51 +++++++++++++++++-- .../AbstractApiBasedModel.php | 26 ++++++++++ .../Models/Contracts/ModelInterface.php | 20 ++++++++ tests/mocks/MockModel.php | 22 ++++++++ tests/traits/MockModelCreationTrait.php | 23 +++++++++ tests/unit/Builders/PromptBuilderTest.php | 45 ++++++++++++++++ 6 files changed, 182 insertions(+), 5 deletions(-) diff --git a/src/Builders/PromptBuilder.php b/src/Builders/PromptBuilder.php index 047fb4ec..fb7ba533 100644 --- a/src/Builders/PromptBuilder.php +++ b/src/Builders/PromptBuilder.php @@ -13,6 +13,7 @@ use WordPress\AiClient\Messages\DTO\UserMessage; use WordPress\AiClient\Messages\Enums\MessageRoleEnum; use WordPress\AiClient\Messages\Enums\ModalityEnum; +use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -75,6 +76,11 @@ class PromptBuilder */ protected ModelConfig $modelConfig; + /** + * @var RequestOptions|null The request options for HTTP transport. + */ + protected ?RequestOptions $requestOptions = null; + // phpcs:disable Generic.Files.LineLength.TooLong /** * Constructor. @@ -482,6 +488,20 @@ public function usingWebSearch(WebSearch $webSearch): self return $this; } + /** + * Sets the request options for HTTP transport. + * + * @since n.e.x.t + * + * @param RequestOptions $requestOptions The request options. + * @return self + */ + public function usingRequestOptions(RequestOptions $requestOptions): self + { + $this->requestOptions = $requestOptions; + return $this; + } + /** * Sets the top log probabilities configuration. * @@ -1112,9 +1132,11 @@ private function getConfiguredModel(CapabilityEnum $capability): ModelInterface if ($this->model !== null) { // Explicit model was provided via usingModel(); just update config and bind dependencies. - $this->model->setConfig($this->modelConfig); - $this->registry->bindModelDependencies($this->model); - return $this->model; + $model = $this->model; + $model->setConfig($this->modelConfig); + $this->registry->bindModelDependencies($model); + $this->bindModelRequestOptions($model); + return $model; } // Retrieve the candidate models map which satisfies the requirements. @@ -1150,14 +1172,33 @@ private function getConfiguredModel(CapabilityEnum $capability): ModelInterface $firstMatchKey = key($matchingPreferences); [$providerId, $modelId] = $candidateMap[$firstMatchKey]; - return $this->registry->getProviderModel($providerId, $modelId, $this->modelConfig); + $model = $this->registry->getProviderModel($providerId, $modelId, $this->modelConfig); + $this->bindModelRequestOptions($model); + return $model; } } // No preference matched; fall back to the first candidate discovered. [$providerId, $modelId] = reset($candidateMap); - return $this->registry->getProviderModel($providerId, $modelId, $this->modelConfig); + $model = $this->registry->getProviderModel($providerId, $modelId, $this->modelConfig); + $this->bindModelRequestOptions($model); + return $model; + } + + /** + * Binds configured request options to the model if present. + * + * @since n.e.x.t + * + * @param ModelInterface $model The model to bind request options to. + * @return void + */ + private function bindModelRequestOptions(ModelInterface $model): void + { + if ($this->requestOptions !== null) { + $model->setRequestOptions($this->requestOptions); + } } /** diff --git a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php index cc9760ef..a72dc83a 100644 --- a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php +++ b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php @@ -7,6 +7,7 @@ use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\Http\Contracts\WithHttpTransporterInterface; use WordPress\AiClient\Providers\Http\Contracts\WithRequestAuthenticationInterface; +use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Http\Traits\WithHttpTransporterTrait; use WordPress\AiClient\Providers\Http\Traits\WithRequestAuthenticationTrait; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; @@ -44,6 +45,11 @@ abstract class AbstractApiBasedModel implements */ private ModelConfig $config; + /** + * @var RequestOptions|null The request options for HTTP transport. + */ + private ?RequestOptions $requestOptions = null; + /** * Constructor. * @@ -98,4 +104,24 @@ final public function getConfig(): ModelConfig { return $this->config; } + + /** + * {@inheritDoc} + * + * @since n.e.x.t + */ + final public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + /** + * {@inheritDoc} + * + * @since n.e.x.t + */ + final public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } } diff --git a/src/Providers/Models/Contracts/ModelInterface.php b/src/Providers/Models/Contracts/ModelInterface.php index c0a48830..6e1e38bb 100644 --- a/src/Providers/Models/Contracts/ModelInterface.php +++ b/src/Providers/Models/Contracts/ModelInterface.php @@ -5,6 +5,7 @@ namespace WordPress\AiClient\Providers\Models\Contracts; use WordPress\AiClient\Providers\DTO\ProviderMetadata; +use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -54,4 +55,23 @@ public function setConfig(ModelConfig $config): void; * @return ModelConfig Current model configuration. */ public function getConfig(): ModelConfig; + + /** + * Sets request options for HTTP transport. + * + * @since n.e.x.t + * + * @param RequestOptions $requestOptions Request options. + * @return void + */ + public function setRequestOptions(RequestOptions $requestOptions): void; + + /** + * Gets request options for HTTP transport. + * + * @since n.e.x.t + * + * @return RequestOptions|null Current request options, or null if not set. + */ + public function getRequestOptions(): ?RequestOptions; } diff --git a/tests/mocks/MockModel.php b/tests/mocks/MockModel.php index 13d4a9a2..29f1ff94 100644 --- a/tests/mocks/MockModel.php +++ b/tests/mocks/MockModel.php @@ -7,6 +7,7 @@ use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\Http\Contracts\WithHttpTransporterInterface; use WordPress\AiClient\Providers\Http\Contracts\WithRequestAuthenticationInterface; +use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Http\Traits\WithHttpTransporterTrait; use WordPress\AiClient\Providers\Http\Traits\WithRequestAuthenticationTrait; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; @@ -31,6 +32,11 @@ class MockModel implements ModelInterface, WithHttpTransporterInterface, WithReq */ private ModelConfig $config; + /** + * @var RequestOptions|null The request options. + */ + private ?RequestOptions $requestOptions = null; + /** * Constructor. * @@ -75,4 +81,20 @@ public function setConfig(ModelConfig $config): void { $this->config = $config; } + + /** + * {@inheritDoc} + */ + public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + /** + * {@inheritDoc} + */ + public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } } diff --git a/tests/traits/MockModelCreationTrait.php b/tests/traits/MockModelCreationTrait.php index ecf033c8..642c043a 100644 --- a/tests/traits/MockModelCreationTrait.php +++ b/tests/traits/MockModelCreationTrait.php @@ -9,6 +9,7 @@ use WordPress\AiClient\Messages\DTO\ModelMessage; use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\Enums\ProviderTypeEnum; +use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -142,6 +143,7 @@ protected function createMockTextGenerationModel( private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; + private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -174,6 +176,16 @@ public function getConfig(): ModelConfig return $this->config; } + public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } + public function generateTextResult(array $prompt): GenerativeAiResult { return $this->result; @@ -214,6 +226,7 @@ protected function createMockImageGenerationModel( private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; + private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -246,6 +259,16 @@ public function getConfig(): ModelConfig return $this->config; } + public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } + public function generateImageResult(array $prompt): GenerativeAiResult { return $this->result; diff --git a/tests/unit/Builders/PromptBuilderTest.php b/tests/unit/Builders/PromptBuilderTest.php index de23054a..6a2a703e 100644 --- a/tests/unit/Builders/PromptBuilderTest.php +++ b/tests/unit/Builders/PromptBuilderTest.php @@ -20,6 +20,7 @@ use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\DTO\ProviderModelsMetadata; use WordPress\AiClient\Providers\Enums\ProviderTypeEnum; +use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -105,6 +106,7 @@ private function createSpeechGenerationModel(ModelMetadata $metadata, Generative private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; + private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -137,6 +139,16 @@ public function getConfig(): ModelConfig return $this->config; } + public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } + public function generateSpeechResult(array $prompt): GenerativeAiResult { return $this->result; @@ -168,6 +180,7 @@ private function createTextToSpeechModel(ModelMetadata $metadata, GenerativeAiRe private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; + private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -200,6 +213,16 @@ public function getConfig(): ModelConfig return $this->config; } + public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } + public function convertTextToSpeechResult(array $prompt): GenerativeAiResult { return $this->result; @@ -1916,6 +1939,7 @@ public function testGenerateTextThrowsExceptionWhenNoCandidates(): void private ModelMetadata $metadata; private ProviderMetadata $providerMetadata; private ModelConfig $config; + private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -1946,6 +1970,16 @@ public function getConfig(): ModelConfig return $this->config; } + public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } + public function generateTextResult(array $prompt): GenerativeAiResult { throw new RuntimeException('No candidates were generated'); @@ -2110,6 +2144,7 @@ public function testGenerateTextsThrowsExceptionWhenNoTextGenerated(): void private ModelMetadata $metadata; private ProviderMetadata $providerMetadata; private ModelConfig $config; + private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -2140,6 +2175,16 @@ public function getConfig(): ModelConfig return $this->config; } + public function setRequestOptions(RequestOptions $requestOptions): void + { + $this->requestOptions = $requestOptions; + } + + public function getRequestOptions(): ?RequestOptions + { + return $this->requestOptions; + } + public function generateTextResult(array $prompt): GenerativeAiResult { throw new RuntimeException('No text was generated from any candidates'); From bedb51adf8c3d8afc237878f585b4b8d79682116 Mon Sep 17 00:00:00 2001 From: Jason Adams Date: Wed, 26 Nov 2025 14:36:18 -0700 Subject: [PATCH 2/4] feat: binds request options to model requests --- src/Builders/PromptBuilder.php | 7 ++- .../AnthropicTextGenerationModel.php | 11 +++-- .../Google/GoogleImageGenerationModel.php | 11 +++-- .../Google/GoogleTextGenerationModel.php | 11 +++-- .../OpenAi/OpenAiImageGenerationModel.php | 11 +++-- .../OpenAi/OpenAiTextGenerationModel.php | 11 +++-- .../Models/Contracts/ModelInterface.php | 20 --------- ...ctOpenAiCompatibleImageGenerationModel.php | 3 ++ ...actOpenAiCompatibleTextGenerationModel.php | 3 ++ tests/mocks/MockModel.php | 22 --------- ...ckOpenAiCompatibleImageGenerationModel.php | 2 +- tests/traits/MockModelCreationTrait.php | 23 ---------- tests/unit/Builders/PromptBuilderTest.php | 45 ------------------- ...ockOpenAiCompatibleTextGenerationModel.php | 2 +- 14 files changed, 53 insertions(+), 129 deletions(-) diff --git a/src/Builders/PromptBuilder.php b/src/Builders/PromptBuilder.php index fb7ba533..331ca642 100644 --- a/src/Builders/PromptBuilder.php +++ b/src/Builders/PromptBuilder.php @@ -13,6 +13,7 @@ use WordPress\AiClient\Messages\DTO\UserMessage; use WordPress\AiClient\Messages\Enums\MessageRoleEnum; use WordPress\AiClient\Messages\Enums\ModalityEnum; +use WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModel; use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; @@ -1187,7 +1188,9 @@ private function getConfiguredModel(CapabilityEnum $capability): ModelInterface } /** - * Binds configured request options to the model if present. + * Binds configured request options to the model if present and supported. + * + * Request options are only applicable to API-based models that make HTTP requests. * * @since n.e.x.t * @@ -1196,7 +1199,7 @@ private function getConfiguredModel(CapabilityEnum $capability): ModelInterface */ private function bindModelRequestOptions(ModelInterface $model): void { - if ($this->requestOptions !== null) { + if ($this->requestOptions !== null && $model instanceof AbstractApiBasedModel) { $model->setRequestOptions($this->requestOptions); } } diff --git a/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php b/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php index e2aaf0ae..76e6eda6 100644 --- a/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php +++ b/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php @@ -20,13 +20,18 @@ class AnthropicTextGenerationModel extends AbstractOpenAiCompatibleTextGeneratio * * @since 0.1.0 */ - protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request - { + protected function createRequest( + HttpMethodEnum $method, + string $path, + array $headers = [], + $data = null + ): Request { return new Request( $method, AnthropicProvider::url($path), $headers, - $data + $data, + $this->getRequestOptions() ); } } diff --git a/src/ProviderImplementations/Google/GoogleImageGenerationModel.php b/src/ProviderImplementations/Google/GoogleImageGenerationModel.php index e3650848..6bafab7f 100644 --- a/src/ProviderImplementations/Google/GoogleImageGenerationModel.php +++ b/src/ProviderImplementations/Google/GoogleImageGenerationModel.php @@ -18,13 +18,18 @@ class GoogleImageGenerationModel extends AbstractOpenAiCompatibleImageGeneration /** * @inheritDoc */ - protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request - { + protected function createRequest( + HttpMethodEnum $method, + string $path, + array $headers = [], + $data = null + ): Request { return new Request( $method, GoogleProvider::url('openai/' . ltrim($path, '/')), $headers, - $data + $data, + $this->getRequestOptions() ); } } diff --git a/src/ProviderImplementations/Google/GoogleTextGenerationModel.php b/src/ProviderImplementations/Google/GoogleTextGenerationModel.php index 8ad63289..284a38d3 100644 --- a/src/ProviderImplementations/Google/GoogleTextGenerationModel.php +++ b/src/ProviderImplementations/Google/GoogleTextGenerationModel.php @@ -20,13 +20,18 @@ class GoogleTextGenerationModel extends AbstractOpenAiCompatibleTextGenerationMo * * @since 0.1.0 */ - protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request - { + protected function createRequest( + HttpMethodEnum $method, + string $path, + array $headers = [], + $data = null + ): Request { return new Request( $method, GoogleProvider::url('openai/' . ltrim($path, '/')), $headers, - $data + $data, + $this->getRequestOptions() ); } } diff --git a/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php b/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php index dbb20c00..1e4a499f 100644 --- a/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php +++ b/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php @@ -18,13 +18,18 @@ class OpenAiImageGenerationModel extends AbstractOpenAiCompatibleImageGeneration /** * @inheritDoc */ - protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request - { + protected function createRequest( + HttpMethodEnum $method, + string $path, + array $headers = [], + $data = null + ): Request { return new Request( $method, OpenAiProvider::url($path), $headers, - $data + $data, + $this->getRequestOptions() ); } diff --git a/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php b/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php index 75220a37..f21a28a3 100644 --- a/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php +++ b/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php @@ -20,13 +20,18 @@ class OpenAiTextGenerationModel extends AbstractOpenAiCompatibleTextGenerationMo * * @since 0.1.0 */ - protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request - { + protected function createRequest( + HttpMethodEnum $method, + string $path, + array $headers = [], + $data = null + ): Request { return new Request( $method, OpenAiProvider::url($path), $headers, - $data + $data, + $this->getRequestOptions() ); } } diff --git a/src/Providers/Models/Contracts/ModelInterface.php b/src/Providers/Models/Contracts/ModelInterface.php index 6e1e38bb..c0a48830 100644 --- a/src/Providers/Models/Contracts/ModelInterface.php +++ b/src/Providers/Models/Contracts/ModelInterface.php @@ -5,7 +5,6 @@ namespace WordPress\AiClient\Providers\Models\Contracts; use WordPress\AiClient\Providers\DTO\ProviderMetadata; -use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -55,23 +54,4 @@ public function setConfig(ModelConfig $config): void; * @return ModelConfig Current model configuration. */ public function getConfig(): ModelConfig; - - /** - * Sets request options for HTTP transport. - * - * @since n.e.x.t - * - * @param RequestOptions $requestOptions Request options. - * @return void - */ - public function setRequestOptions(RequestOptions $requestOptions): void; - - /** - * Gets request options for HTTP transport. - * - * @since n.e.x.t - * - * @return RequestOptions|null Current request options, or null if not set. - */ - public function getRequestOptions(): ?RequestOptions; } diff --git a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php index ff5d5105..f830b54e 100644 --- a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php +++ b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php @@ -249,6 +249,9 @@ protected function prepareSizeParam(?MediaOrientationEnum $orientation, ?string /** * Creates a request object for the provider's API. * + * Implementations should use $this->getRequestOptions() to attach any + * configured request options to the Request. + * * @since 0.1.0 * * @param HttpMethodEnum $method The HTTP method. diff --git a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php index 1f345c96..a630746b 100644 --- a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php +++ b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php @@ -536,6 +536,9 @@ protected function prepareResponseFormatParam(?array $outputSchema): array /** * Creates a request object for the provider's API. * + * Implementations should use $this->getRequestOptions() to attach any + * configured request options to the Request. + * * @since 0.1.0 * * @param HttpMethodEnum $method The HTTP method. diff --git a/tests/mocks/MockModel.php b/tests/mocks/MockModel.php index 29f1ff94..13d4a9a2 100644 --- a/tests/mocks/MockModel.php +++ b/tests/mocks/MockModel.php @@ -7,7 +7,6 @@ use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\Http\Contracts\WithHttpTransporterInterface; use WordPress\AiClient\Providers\Http\Contracts\WithRequestAuthenticationInterface; -use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Http\Traits\WithHttpTransporterTrait; use WordPress\AiClient\Providers\Http\Traits\WithRequestAuthenticationTrait; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; @@ -32,11 +31,6 @@ class MockModel implements ModelInterface, WithHttpTransporterInterface, WithReq */ private ModelConfig $config; - /** - * @var RequestOptions|null The request options. - */ - private ?RequestOptions $requestOptions = null; - /** * Constructor. * @@ -81,20 +75,4 @@ public function setConfig(ModelConfig $config): void { $this->config = $config; } - - /** - * {@inheritDoc} - */ - public function setRequestOptions(RequestOptions $requestOptions): void - { - $this->requestOptions = $requestOptions; - } - - /** - * {@inheritDoc} - */ - public function getRequestOptions(): ?RequestOptions - { - return $this->requestOptions; - } } diff --git a/tests/mocks/MockOpenAiCompatibleImageGenerationModel.php b/tests/mocks/MockOpenAiCompatibleImageGenerationModel.php index c9383082..4ea104b6 100644 --- a/tests/mocks/MockOpenAiCompatibleImageGenerationModel.php +++ b/tests/mocks/MockOpenAiCompatibleImageGenerationModel.php @@ -26,7 +26,7 @@ protected function createRequest( array $headers = [], $data = null ): Request { - return new Request($method, $path, $headers, $data); + return new Request($method, $path, $headers, $data, $this->getRequestOptions()); } /** diff --git a/tests/traits/MockModelCreationTrait.php b/tests/traits/MockModelCreationTrait.php index 642c043a..ecf033c8 100644 --- a/tests/traits/MockModelCreationTrait.php +++ b/tests/traits/MockModelCreationTrait.php @@ -9,7 +9,6 @@ use WordPress\AiClient\Messages\DTO\ModelMessage; use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\Enums\ProviderTypeEnum; -use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -143,7 +142,6 @@ protected function createMockTextGenerationModel( private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; - private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -176,16 +174,6 @@ public function getConfig(): ModelConfig return $this->config; } - public function setRequestOptions(RequestOptions $requestOptions): void - { - $this->requestOptions = $requestOptions; - } - - public function getRequestOptions(): ?RequestOptions - { - return $this->requestOptions; - } - public function generateTextResult(array $prompt): GenerativeAiResult { return $this->result; @@ -226,7 +214,6 @@ protected function createMockImageGenerationModel( private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; - private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -259,16 +246,6 @@ public function getConfig(): ModelConfig return $this->config; } - public function setRequestOptions(RequestOptions $requestOptions): void - { - $this->requestOptions = $requestOptions; - } - - public function getRequestOptions(): ?RequestOptions - { - return $this->requestOptions; - } - public function generateImageResult(array $prompt): GenerativeAiResult { return $this->result; diff --git a/tests/unit/Builders/PromptBuilderTest.php b/tests/unit/Builders/PromptBuilderTest.php index 6a2a703e..de23054a 100644 --- a/tests/unit/Builders/PromptBuilderTest.php +++ b/tests/unit/Builders/PromptBuilderTest.php @@ -20,7 +20,6 @@ use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\DTO\ProviderModelsMetadata; use WordPress\AiClient\Providers\Enums\ProviderTypeEnum; -use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -106,7 +105,6 @@ private function createSpeechGenerationModel(ModelMetadata $metadata, Generative private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; - private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -139,16 +137,6 @@ public function getConfig(): ModelConfig return $this->config; } - public function setRequestOptions(RequestOptions $requestOptions): void - { - $this->requestOptions = $requestOptions; - } - - public function getRequestOptions(): ?RequestOptions - { - return $this->requestOptions; - } - public function generateSpeechResult(array $prompt): GenerativeAiResult { return $this->result; @@ -180,7 +168,6 @@ private function createTextToSpeechModel(ModelMetadata $metadata, GenerativeAiRe private ProviderMetadata $providerMetadata; private GenerativeAiResult $result; private ModelConfig $config; - private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -213,16 +200,6 @@ public function getConfig(): ModelConfig return $this->config; } - public function setRequestOptions(RequestOptions $requestOptions): void - { - $this->requestOptions = $requestOptions; - } - - public function getRequestOptions(): ?RequestOptions - { - return $this->requestOptions; - } - public function convertTextToSpeechResult(array $prompt): GenerativeAiResult { return $this->result; @@ -1939,7 +1916,6 @@ public function testGenerateTextThrowsExceptionWhenNoCandidates(): void private ModelMetadata $metadata; private ProviderMetadata $providerMetadata; private ModelConfig $config; - private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -1970,16 +1946,6 @@ public function getConfig(): ModelConfig return $this->config; } - public function setRequestOptions(RequestOptions $requestOptions): void - { - $this->requestOptions = $requestOptions; - } - - public function getRequestOptions(): ?RequestOptions - { - return $this->requestOptions; - } - public function generateTextResult(array $prompt): GenerativeAiResult { throw new RuntimeException('No candidates were generated'); @@ -2144,7 +2110,6 @@ public function testGenerateTextsThrowsExceptionWhenNoTextGenerated(): void private ModelMetadata $metadata; private ProviderMetadata $providerMetadata; private ModelConfig $config; - private ?RequestOptions $requestOptions = null; public function __construct( ModelMetadata $metadata, @@ -2175,16 +2140,6 @@ public function getConfig(): ModelConfig return $this->config; } - public function setRequestOptions(RequestOptions $requestOptions): void - { - $this->requestOptions = $requestOptions; - } - - public function getRequestOptions(): ?RequestOptions - { - return $this->requestOptions; - } - public function generateTextResult(array $prompt): GenerativeAiResult { throw new RuntimeException('No text was generated from any candidates'); diff --git a/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleTextGenerationModel.php b/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleTextGenerationModel.php index 3e33c61f..4ddd3d7f 100644 --- a/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleTextGenerationModel.php +++ b/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleTextGenerationModel.php @@ -82,7 +82,7 @@ protected function createRequest( array $headers = [], $data = null ): Request { - return new Request($method, 'https://example.com/' . $path, $headers, $data); + return new Request($method, 'https://example.com/' . $path, $headers, $data, $this->getRequestOptions()); } /** From 9478f4cdcf271eb897ec1feb42eea0ebb32bf3bc Mon Sep 17 00:00:00 2001 From: Jason Adams Date: Wed, 26 Nov 2025 14:43:32 -0700 Subject: [PATCH 3/4] revert: sets unnecesary formatting change back --- .../Anthropic/AnthropicTextGenerationModel.php | 8 ++------ .../Google/GoogleImageGenerationModel.php | 8 ++------ .../Google/GoogleTextGenerationModel.php | 8 ++------ .../OpenAi/OpenAiImageGenerationModel.php | 8 ++------ .../OpenAi/OpenAiTextGenerationModel.php | 8 ++------ 5 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php b/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php index 76e6eda6..ed4a5a15 100644 --- a/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php +++ b/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php @@ -20,12 +20,8 @@ class AnthropicTextGenerationModel extends AbstractOpenAiCompatibleTextGeneratio * * @since 0.1.0 */ - protected function createRequest( - HttpMethodEnum $method, - string $path, - array $headers = [], - $data = null - ): Request { + protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request + { return new Request( $method, AnthropicProvider::url($path), diff --git a/src/ProviderImplementations/Google/GoogleImageGenerationModel.php b/src/ProviderImplementations/Google/GoogleImageGenerationModel.php index 6bafab7f..830fd868 100644 --- a/src/ProviderImplementations/Google/GoogleImageGenerationModel.php +++ b/src/ProviderImplementations/Google/GoogleImageGenerationModel.php @@ -18,12 +18,8 @@ class GoogleImageGenerationModel extends AbstractOpenAiCompatibleImageGeneration /** * @inheritDoc */ - protected function createRequest( - HttpMethodEnum $method, - string $path, - array $headers = [], - $data = null - ): Request { + protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request + { return new Request( $method, GoogleProvider::url('openai/' . ltrim($path, '/')), diff --git a/src/ProviderImplementations/Google/GoogleTextGenerationModel.php b/src/ProviderImplementations/Google/GoogleTextGenerationModel.php index 284a38d3..9bf66fa1 100644 --- a/src/ProviderImplementations/Google/GoogleTextGenerationModel.php +++ b/src/ProviderImplementations/Google/GoogleTextGenerationModel.php @@ -20,12 +20,8 @@ class GoogleTextGenerationModel extends AbstractOpenAiCompatibleTextGenerationMo * * @since 0.1.0 */ - protected function createRequest( - HttpMethodEnum $method, - string $path, - array $headers = [], - $data = null - ): Request { + protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request + { return new Request( $method, GoogleProvider::url('openai/' . ltrim($path, '/')), diff --git a/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php b/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php index 1e4a499f..5049e964 100644 --- a/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php +++ b/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php @@ -18,12 +18,8 @@ class OpenAiImageGenerationModel extends AbstractOpenAiCompatibleImageGeneration /** * @inheritDoc */ - protected function createRequest( - HttpMethodEnum $method, - string $path, - array $headers = [], - $data = null - ): Request { + protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request + { return new Request( $method, OpenAiProvider::url($path), diff --git a/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php b/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php index f21a28a3..6d679e4b 100644 --- a/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php +++ b/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php @@ -20,12 +20,8 @@ class OpenAiTextGenerationModel extends AbstractOpenAiCompatibleTextGenerationMo * * @since 0.1.0 */ - protected function createRequest( - HttpMethodEnum $method, - string $path, - array $headers = [], - $data = null - ): Request { + protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request + { return new Request( $method, OpenAiProvider::url($path), From f4cf2a7b334b7127dc8407db7ea25ed0f033d1a3 Mon Sep 17 00:00:00 2001 From: Jason Adams Date: Wed, 26 Nov 2025 16:39:17 -0700 Subject: [PATCH 4/4] refactor: adds ApiBasedModelInterface --- src/Builders/PromptBuilder.php | 4 +- .../AbstractApiBasedModel.php | 4 +- .../Contracts/ApiBasedModelInterface.php | 38 +++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php diff --git a/src/Builders/PromptBuilder.php b/src/Builders/PromptBuilder.php index 331ca642..758aeeda 100644 --- a/src/Builders/PromptBuilder.php +++ b/src/Builders/PromptBuilder.php @@ -13,7 +13,7 @@ use WordPress\AiClient\Messages\DTO\UserMessage; use WordPress\AiClient\Messages\Enums\MessageRoleEnum; use WordPress\AiClient\Messages\Enums\ModalityEnum; -use WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModel; +use WordPress\AiClient\Providers\ApiBasedImplementation\Contracts\ApiBasedModelInterface; use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; @@ -1199,7 +1199,7 @@ private function getConfiguredModel(CapabilityEnum $capability): ModelInterface */ private function bindModelRequestOptions(ModelInterface $model): void { - if ($this->requestOptions !== null && $model instanceof AbstractApiBasedModel) { + if ($this->requestOptions !== null && $model instanceof ApiBasedModelInterface) { $model->setRequestOptions($this->requestOptions); } } diff --git a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php index a72dc83a..e1a93e5e 100644 --- a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php +++ b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php @@ -4,13 +4,13 @@ namespace WordPress\AiClient\Providers\ApiBasedImplementation; +use WordPress\AiClient\Providers\ApiBasedImplementation\Contracts\ApiBasedModelInterface; use WordPress\AiClient\Providers\DTO\ProviderMetadata; use WordPress\AiClient\Providers\Http\Contracts\WithHttpTransporterInterface; use WordPress\AiClient\Providers\Http\Contracts\WithRequestAuthenticationInterface; use WordPress\AiClient\Providers\Http\DTO\RequestOptions; use WordPress\AiClient\Providers\Http\Traits\WithHttpTransporterTrait; use WordPress\AiClient\Providers\Http\Traits\WithRequestAuthenticationTrait; -use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; use WordPress\AiClient\Providers\Models\DTO\ModelConfig; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -23,7 +23,7 @@ * @since 0.1.0 */ abstract class AbstractApiBasedModel implements - ModelInterface, + ApiBasedModelInterface, WithHttpTransporterInterface, WithRequestAuthenticationInterface { diff --git a/src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php b/src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php new file mode 100644 index 00000000..e7690365 --- /dev/null +++ b/src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php @@ -0,0 +1,38 @@ +