diff --git a/src/Builders/PromptBuilder.php b/src/Builders/PromptBuilder.php index 047fb4ec..758aeeda 100644 --- a/src/Builders/PromptBuilder.php +++ b/src/Builders/PromptBuilder.php @@ -13,6 +13,8 @@ use WordPress\AiClient\Messages\DTO\UserMessage; use WordPress\AiClient\Messages\Enums\MessageRoleEnum; use WordPress\AiClient\Messages\Enums\ModalityEnum; +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; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; @@ -75,6 +77,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 +489,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 +1133,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 +1173,35 @@ 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 and supported. + * + * Request options are only applicable to API-based models that make HTTP requests. + * + * @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 instanceof ApiBasedModelInterface) { + $model->setRequestOptions($this->requestOptions); + } } /** diff --git a/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php b/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php index e2aaf0ae..ed4a5a15 100644 --- a/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php +++ b/src/ProviderImplementations/Anthropic/AnthropicTextGenerationModel.php @@ -26,7 +26,8 @@ protected function createRequest(HttpMethodEnum $method, string $path, array $he $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..830fd868 100644 --- a/src/ProviderImplementations/Google/GoogleImageGenerationModel.php +++ b/src/ProviderImplementations/Google/GoogleImageGenerationModel.php @@ -24,7 +24,8 @@ protected function createRequest(HttpMethodEnum $method, string $path, array $he $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..9bf66fa1 100644 --- a/src/ProviderImplementations/Google/GoogleTextGenerationModel.php +++ b/src/ProviderImplementations/Google/GoogleTextGenerationModel.php @@ -26,7 +26,8 @@ protected function createRequest(HttpMethodEnum $method, string $path, array $he $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..5049e964 100644 --- a/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php +++ b/src/ProviderImplementations/OpenAi/OpenAiImageGenerationModel.php @@ -24,7 +24,8 @@ protected function createRequest(HttpMethodEnum $method, string $path, array $he $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..6d679e4b 100644 --- a/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php +++ b/src/ProviderImplementations/OpenAi/OpenAiTextGenerationModel.php @@ -26,7 +26,8 @@ protected function createRequest(HttpMethodEnum $method, string $path, array $he $method, OpenAiProvider::url($path), $headers, - $data + $data, + $this->getRequestOptions() ); } } diff --git a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php index cc9760ef..e1a93e5e 100644 --- a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php +++ b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php @@ -4,12 +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; @@ -22,7 +23,7 @@ * @since 0.1.0 */ abstract class AbstractApiBasedModel implements - ModelInterface, + ApiBasedModelInterface, WithHttpTransporterInterface, WithRequestAuthenticationInterface { @@ -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/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 @@ +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/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/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()); } /**