From 3e79f62af33202b9e581ea3bc4b8beedb2b3b45b Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Sat, 2 May 2026 10:56:29 -0400 Subject: [PATCH 1/2] Avoid listing models for explicit text model IDs --- ...AbstractApiBasedModelMetadataDirectory.php | 28 ++++ ...OpenAiCompatibleModelMetadataDirectory.php | 36 +++++ ...ractApiBasedModelMetadataDirectoryTest.php | 68 ++++++++++ .../MockApiBasedModelMetadataDirectory.php | 37 ++++- ...AiCompatibleModelMetadataDirectoryTest.php | 127 ++++++++++++++++++ tests/unit/Providers/ProviderRegistryTest.php | 25 ++++ 6 files changed, 320 insertions(+), 1 deletion(-) diff --git a/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php b/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php index 52c0cd5f..1666183d 100644 --- a/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php +++ b/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php @@ -68,6 +68,18 @@ final public function hasModelMetadata(string $modelId): bool */ final public function getModelMetadata(string $modelId): ModelMetadata { + if ($this->hasCache(self::MODELS_CACHE_KEY)) { + $modelsMetadata = $this->getModelMetadataMap(); + if (isset($modelsMetadata[$modelId])) { + return $modelsMetadata[$modelId]; + } + } + + $explicitModelMetadata = $this->createModelMetadataForExplicitModelId($modelId); + if ($explicitModelMetadata !== null) { + return $explicitModelMetadata; + } + $modelsMetadata = $this->getModelMetadataMap(); if (!isset($modelsMetadata[$modelId])) { throw new InvalidArgumentException( @@ -114,6 +126,22 @@ protected function getBaseCacheKey(): string return 'ai_client_' . AiClient::VERSION . '_' . md5(static::class); } + /** + * Creates metadata for an explicit model ID without listing provider models. + * + * Providers whose APIs accept arbitrary/current model IDs can override this to avoid a live list-models request + * when callers already know the model ID they want to instantiate. + * + * @since n.e.x.t + * + * @param string $modelId The explicit model ID. + * @return ModelMetadata|null The model metadata, or null to fall back to listing provider models. + */ + protected function createModelMetadataForExplicitModelId(string $modelId): ?ModelMetadata + { + return null; + } + /** * Sends the API request to list models from the provider and returns the map of model ID to model metadata. * diff --git a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php index 4a1151a6..cf15c066 100644 --- a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php +++ b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php @@ -11,6 +11,7 @@ use WordPress\AiClient\Providers\Http\Exception\ResponseException; use WordPress\AiClient\Providers\Http\Util\ResponseUtil; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; +use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum; /** * Base class for a model metadata directory for providers that implement OpenAI's API format. @@ -23,6 +24,41 @@ */ abstract class AbstractOpenAiCompatibleModelMetadataDirectory extends AbstractApiBasedModelMetadataDirectory { + /** + * {@inheritDoc} + * + * @since n.e.x.t + */ + protected function createModelMetadataForExplicitModelId(string $modelId): ?ModelMetadata + { + if (!$this->isExplicitTextGenerationModelId($modelId)) { + return null; + } + + return new ModelMetadata($modelId, $modelId, [CapabilityEnum::textGeneration()], []); + } + + /** + * Checks whether a model ID is safe to treat as a text generation model without listing models. + * + * @since n.e.x.t + * + * @param string $modelId The explicit model ID. + * @return bool True if the model ID matches common OpenAI-compatible text generation model families. + */ + protected function isExplicitTextGenerationModelId(string $modelId): bool + { + if (str_starts_with($modelId, 'gpt-image-') || str_starts_with($modelId, 'dall-e-')) { + return false; + } + + if (str_starts_with($modelId, 'gpt-') || str_starts_with($modelId, 'chatgpt-')) { + return true; + } + + return preg_match('/^o\d(?:-|$)/', $modelId) === 1; + } + /** * {@inheritDoc} * diff --git a/tests/unit/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectoryTest.php b/tests/unit/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectoryTest.php index 0313453c..f8a8204c 100644 --- a/tests/unit/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectoryTest.php +++ b/tests/unit/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectoryTest.php @@ -6,7 +6,9 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; +use WordPress\AiClient\AiClient; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; +use WordPress\AiClient\Tests\mocks\MockCache; /** * @covers \WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModelMetadataDirectory @@ -28,6 +30,13 @@ protected function setUp(): void ]; } + protected function tearDown(): void + { + AiClient::setCache(null); + + parent::tearDown(); + } + /** * Tests listModelMetadata() method. * @@ -69,6 +78,65 @@ public function testGetModelMetadata(): void $this->assertSame($this->mockModels['model-1'], $directory->getModelMetadata('model-1')); } + /** + * Tests getModelMetadata() returns explicit metadata without listing models. + * + * @return void + */ + public function testGetModelMetadataReturnsExplicitMetadataWithoutListingModels(): void + { + $explicitModelMetadata = $this->createStub(ModelMetadata::class); + $explicitModelMetadata->method('getId')->willReturn('explicit-model'); + $directory = new MockApiBasedModelMetadataDirectory([], $explicitModelMetadata); + + $this->assertSame($explicitModelMetadata, $directory->getModelMetadata('explicit-model')); + $this->assertSame(0, $directory->getListRequestCount()); + } + + /** + * Tests cached model metadata is preferred over explicit metadata. + * + * @return void + */ + public function testGetModelMetadataPrefersCachedMetadataOverExplicitMetadata(): void + { + $cache = new MockCache(); + $cacheKey = 'ai_client_' . AiClient::VERSION . '_' . md5(MockApiBasedModelMetadataDirectory::class) . '_models'; + $cachedModelMetadata = $this->createStub(ModelMetadata::class); + $cachedModelMetadata->method('getId')->willReturn('explicit-model'); + $cache->seed($cacheKey, ['explicit-model' => $cachedModelMetadata]); + AiClient::setCache($cache); + + $explicitModelMetadata = $this->createStub(ModelMetadata::class); + $explicitModelMetadata->method('getId')->willReturn('explicit-model'); + $directory = new MockApiBasedModelMetadataDirectory([], $explicitModelMetadata); + + $this->assertSame($cachedModelMetadata, $directory->getModelMetadata('explicit-model')); + $this->assertSame(0, $directory->getListRequestCount()); + } + + /** + * Tests cached metadata misses can still fall back to explicit metadata. + * + * @return void + */ + public function testGetModelMetadataUsesExplicitMetadataAfterCachedMetadataMiss(): void + { + $cache = new MockCache(); + $cacheKey = 'ai_client_' . AiClient::VERSION . '_' . md5(MockApiBasedModelMetadataDirectory::class) . '_models'; + $otherModelMetadata = $this->createStub(ModelMetadata::class); + $otherModelMetadata->method('getId')->willReturn('other-model'); + $cache->seed($cacheKey, ['other-model' => $otherModelMetadata]); + AiClient::setCache($cache); + + $explicitModelMetadata = $this->createStub(ModelMetadata::class); + $explicitModelMetadata->method('getId')->willReturn('explicit-model'); + $directory = new MockApiBasedModelMetadataDirectory([], $explicitModelMetadata); + + $this->assertSame($explicitModelMetadata, $directory->getModelMetadata('explicit-model')); + $this->assertSame(0, $directory->getListRequestCount()); + } + /** * Tests getModelMetadata() method with non-existent model. * diff --git a/tests/unit/Providers/ApiBasedImplementation/MockApiBasedModelMetadataDirectory.php b/tests/unit/Providers/ApiBasedImplementation/MockApiBasedModelMetadataDirectory.php index 3635c069..6b5bf518 100644 --- a/tests/unit/Providers/ApiBasedImplementation/MockApiBasedModelMetadataDirectory.php +++ b/tests/unit/Providers/ApiBasedImplementation/MockApiBasedModelMetadataDirectory.php @@ -17,14 +17,25 @@ class MockApiBasedModelMetadataDirectory extends AbstractApiBasedModelMetadataDi */ private array $mockModels; + /** + * @var ModelMetadata|null + */ + private ?ModelMetadata $explicitModelMetadata; + + /** + * @var int + */ + private int $listRequestCount = 0; + /** * Constructor. * * @param array $mockModels */ - public function __construct(array $mockModels = []) + public function __construct(array $mockModels = [], ?ModelMetadata $explicitModelMetadata = null) { $this->mockModels = $mockModels; + $this->explicitModelMetadata = $explicitModelMetadata; } /** @@ -32,6 +43,30 @@ public function __construct(array $mockModels = []) */ protected function sendListModelsRequest(): array { + ++$this->listRequestCount; + return $this->mockModels; } + + /** + * @inheritdoc + */ + protected function createModelMetadataForExplicitModelId(string $modelId): ?ModelMetadata + { + if ($this->explicitModelMetadata !== null && $this->explicitModelMetadata->getId() === $modelId) { + return $this->explicitModelMetadata; + } + + return parent::createModelMetadataForExplicitModelId($modelId); + } + + /** + * Returns the number of list request callbacks. + * + * @return int + */ + public function getListRequestCount(): int + { + return $this->listRequestCount; + } } diff --git a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php index f8e79541..08c75286 100644 --- a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php +++ b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php @@ -11,6 +11,7 @@ use WordPress\AiClient\Providers\Http\DTO\Response; use WordPress\AiClient\Providers\Http\Exception\ClientException; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; +use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum; use WordPress\AiClient\Tests\mocks\MockCache; /** @@ -265,6 +266,132 @@ public function testSendListModelsRequestWorksWithoutCache(): void $this->assertEquals('model-x', $modelsMetadata[0]->getId()); } + /** + * Tests that explicit model metadata does not require listing models from the API. + * + * @return void + */ + public function testGetModelMetadataForExplicitModelIdDoesNotListModels(): void + { + $this->mockHttpTransporter + ->expects($this->never()) + ->method('send'); + + $this->mockRequestAuthentication + ->expects($this->never()) + ->method('authenticateRequest'); + + $directory = new MockOpenAiCompatibleModelMetadataDirectory( + $this->mockHttpTransporter, + $this->mockRequestAuthentication, + null, + [], + true + ); + + $modelMetadata = $directory->getModelMetadata('gpt-5.4'); + + $this->assertEquals('gpt-5.4', $modelMetadata->getId()); + $this->assertEquals('gpt-5.4', $modelMetadata->getName()); + $this->assertEquals([CapabilityEnum::textGeneration()], $modelMetadata->getSupportedCapabilities()); + $this->assertSame([], $modelMetadata->getSupportedOptions()); + } + + /** + * Tests that explicit reasoning model IDs do not require listing models from the API. + * + * @return void + */ + public function testGetModelMetadataForExplicitReasoningModelIdDoesNotListModels(): void + { + $this->mockHttpTransporter + ->expects($this->never()) + ->method('send'); + + $directory = new MockOpenAiCompatibleModelMetadataDirectory( + $this->mockHttpTransporter, + $this->mockRequestAuthentication, + null, + [], + true + ); + + $modelMetadata = $directory->getModelMetadata('o3'); + + $this->assertEquals('o3', $modelMetadata->getId()); + $this->assertEquals([CapabilityEnum::textGeneration()], $modelMetadata->getSupportedCapabilities()); + } + + /** + * Tests that non-text explicit model IDs still use listed model metadata. + * + * @return void + */ + public function testGetModelMetadataForNonTextExplicitModelIdListsModels(): void + { + $response = new Response(200, [], '{"data": [{"id": "gpt-image-1"}]}'); + + $this->mockRequestAuthentication + ->expects($this->once()) + ->method('authenticateRequest') + ->willReturnArgument(0); + + $this->mockHttpTransporter + ->expects($this->once()) + ->method('send') + ->willReturn($response); + + $directory = new MockOpenAiCompatibleModelMetadataDirectory( + $this->mockHttpTransporter, + $this->mockRequestAuthentication, + null, + [], + true + ); + + $modelMetadata = $directory->getModelMetadata('gpt-image-1'); + + $this->assertEquals('gpt-image-1', $modelMetadata->getId()); + } + + /** + * Tests that cached listed metadata wins over synthetic explicit metadata. + * + * @return void + */ + public function testGetModelMetadataUsesCachedListedMetadataWhenAvailable(): void + { + $cache = new MockCache(); + $cacheKey = 'ai_client_' . AiClient::VERSION . '_' + . md5(MockOpenAiCompatibleModelMetadataDirectory::class) . '_models'; + $cache->seed($cacheKey, [ + 'cached-model' => ModelMetadata::fromArray([ + 'id' => 'cached-model', + 'name' => 'Cached Model', + 'supportedCapabilities' => ['text_generation'], + 'supportedOptions' => [], + ]), + ]); + AiClient::setCache($cache); + + $this->mockHttpTransporter + ->expects($this->never()) + ->method('send'); + + $directory = new MockOpenAiCompatibleModelMetadataDirectory( + $this->mockHttpTransporter, + $this->mockRequestAuthentication, + null, + [], + true + ); + + $modelMetadata = $directory->getModelMetadata('cached-model'); + + $this->assertEquals('cached-model', $modelMetadata->getId()); + $this->assertEquals('Cached Model', $modelMetadata->getName()); + } + /** * Tests that cache keys are unique per child class. * diff --git a/tests/unit/Providers/ProviderRegistryTest.php b/tests/unit/Providers/ProviderRegistryTest.php index ff8197e6..214bb8ad 100644 --- a/tests/unit/Providers/ProviderRegistryTest.php +++ b/tests/unit/Providers/ProviderRegistryTest.php @@ -6,6 +6,7 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; +use WordPress\AiClient\Providers\Http\Contracts\HttpTransporterInterface; use WordPress\AiClient\Providers\Http\Contracts\RequestAuthenticationInterface; use WordPress\AiClient\Providers\Http\DTO\ApiKeyRequestAuthentication; use WordPress\AiClient\Providers\Http\DTO\Request; @@ -20,6 +21,8 @@ use WordPress\AiClient\Tests\mocks\MockNoAuthProvider; use WordPress\AiClient\Tests\mocks\MockProvider; use WordPress\AiClient\Tests\mocks\MockProviderAvailability; +use WordPress\OpenAiAiProvider\Models\OpenAiTextGenerationModel; +use WordPress\OpenAiAiProvider\Provider\OpenAiProvider; /** * @covers \WordPress\AiClient\Providers\ProviderRegistry @@ -228,6 +231,28 @@ public function testGetProviderModelThrowsException(): void $this->registry->getProviderModel('mock', 'test-model', $modelConfig); } + /** + * Tests that explicit OpenAI model IDs instantiate without listing provider models. + * + * @return void + */ + public function testGetProviderModelWithExplicitOpenAiModelIdDoesNotListModels(): void + { + $httpTransporter = $this->createMock(HttpTransporterInterface::class); + $httpTransporter + ->expects($this->never()) + ->method('send'); + + $this->registry->setHttpTransporter($httpTransporter); + $this->registry->registerProvider(OpenAiProvider::class); + $this->registry->setProviderRequestAuthentication('openai', new ApiKeyRequestAuthentication('test-api-key')); + + $model = $this->registry->getProviderModel('openai', 'gpt-5.4', new ModelConfig([])); + + $this->assertInstanceOf(OpenAiTextGenerationModel::class, $model); + $this->assertEquals('gpt-5.4', $model->metadata()->getId()); + } + /** * Tests multiple provider registration. * From 123286e14d254dfe6cc804624daa0e3ca86e50fd Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Thu, 7 May 2026 10:10:05 -0400 Subject: [PATCH 2/2] Move OpenAI-specific explicit-model logic out of OpenAI-compatible base The OpenAI-compatible abstraction is about HTTP/JSON shape, not OpenAI's model namespace. Drop the gpt-/o3/dall-e prefix gating and the synthetic text-generation metadata override; the per-provider override belongs in ai-provider-for-openai (and similar repos for other compatible providers). The generic createModelMetadataForExplicitModelId() hook on AbstractApiBasedModelMetadataDirectory is unchanged so providers can still opt in. --- ...OpenAiCompatibleModelMetadataDirectory.php | 36 ----- ...AiCompatibleModelMetadataDirectoryTest.php | 127 ------------------ tests/unit/Providers/ProviderRegistryTest.php | 25 ---- 3 files changed, 188 deletions(-) diff --git a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php index cf15c066..4a1151a6 100644 --- a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php +++ b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php @@ -11,7 +11,6 @@ use WordPress\AiClient\Providers\Http\Exception\ResponseException; use WordPress\AiClient\Providers\Http\Util\ResponseUtil; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; -use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum; /** * Base class for a model metadata directory for providers that implement OpenAI's API format. @@ -24,41 +23,6 @@ */ abstract class AbstractOpenAiCompatibleModelMetadataDirectory extends AbstractApiBasedModelMetadataDirectory { - /** - * {@inheritDoc} - * - * @since n.e.x.t - */ - protected function createModelMetadataForExplicitModelId(string $modelId): ?ModelMetadata - { - if (!$this->isExplicitTextGenerationModelId($modelId)) { - return null; - } - - return new ModelMetadata($modelId, $modelId, [CapabilityEnum::textGeneration()], []); - } - - /** - * Checks whether a model ID is safe to treat as a text generation model without listing models. - * - * @since n.e.x.t - * - * @param string $modelId The explicit model ID. - * @return bool True if the model ID matches common OpenAI-compatible text generation model families. - */ - protected function isExplicitTextGenerationModelId(string $modelId): bool - { - if (str_starts_with($modelId, 'gpt-image-') || str_starts_with($modelId, 'dall-e-')) { - return false; - } - - if (str_starts_with($modelId, 'gpt-') || str_starts_with($modelId, 'chatgpt-')) { - return true; - } - - return preg_match('/^o\d(?:-|$)/', $modelId) === 1; - } - /** * {@inheritDoc} * diff --git a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php index 08c75286..f8e79541 100644 --- a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php +++ b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php @@ -11,7 +11,6 @@ use WordPress\AiClient\Providers\Http\DTO\Response; use WordPress\AiClient\Providers\Http\Exception\ClientException; use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; -use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum; use WordPress\AiClient\Tests\mocks\MockCache; /** @@ -266,132 +265,6 @@ public function testSendListModelsRequestWorksWithoutCache(): void $this->assertEquals('model-x', $modelsMetadata[0]->getId()); } - /** - * Tests that explicit model metadata does not require listing models from the API. - * - * @return void - */ - public function testGetModelMetadataForExplicitModelIdDoesNotListModels(): void - { - $this->mockHttpTransporter - ->expects($this->never()) - ->method('send'); - - $this->mockRequestAuthentication - ->expects($this->never()) - ->method('authenticateRequest'); - - $directory = new MockOpenAiCompatibleModelMetadataDirectory( - $this->mockHttpTransporter, - $this->mockRequestAuthentication, - null, - [], - true - ); - - $modelMetadata = $directory->getModelMetadata('gpt-5.4'); - - $this->assertEquals('gpt-5.4', $modelMetadata->getId()); - $this->assertEquals('gpt-5.4', $modelMetadata->getName()); - $this->assertEquals([CapabilityEnum::textGeneration()], $modelMetadata->getSupportedCapabilities()); - $this->assertSame([], $modelMetadata->getSupportedOptions()); - } - - /** - * Tests that explicit reasoning model IDs do not require listing models from the API. - * - * @return void - */ - public function testGetModelMetadataForExplicitReasoningModelIdDoesNotListModels(): void - { - $this->mockHttpTransporter - ->expects($this->never()) - ->method('send'); - - $directory = new MockOpenAiCompatibleModelMetadataDirectory( - $this->mockHttpTransporter, - $this->mockRequestAuthentication, - null, - [], - true - ); - - $modelMetadata = $directory->getModelMetadata('o3'); - - $this->assertEquals('o3', $modelMetadata->getId()); - $this->assertEquals([CapabilityEnum::textGeneration()], $modelMetadata->getSupportedCapabilities()); - } - - /** - * Tests that non-text explicit model IDs still use listed model metadata. - * - * @return void - */ - public function testGetModelMetadataForNonTextExplicitModelIdListsModels(): void - { - $response = new Response(200, [], '{"data": [{"id": "gpt-image-1"}]}'); - - $this->mockRequestAuthentication - ->expects($this->once()) - ->method('authenticateRequest') - ->willReturnArgument(0); - - $this->mockHttpTransporter - ->expects($this->once()) - ->method('send') - ->willReturn($response); - - $directory = new MockOpenAiCompatibleModelMetadataDirectory( - $this->mockHttpTransporter, - $this->mockRequestAuthentication, - null, - [], - true - ); - - $modelMetadata = $directory->getModelMetadata('gpt-image-1'); - - $this->assertEquals('gpt-image-1', $modelMetadata->getId()); - } - - /** - * Tests that cached listed metadata wins over synthetic explicit metadata. - * - * @return void - */ - public function testGetModelMetadataUsesCachedListedMetadataWhenAvailable(): void - { - $cache = new MockCache(); - $cacheKey = 'ai_client_' . AiClient::VERSION . '_' - . md5(MockOpenAiCompatibleModelMetadataDirectory::class) . '_models'; - $cache->seed($cacheKey, [ - 'cached-model' => ModelMetadata::fromArray([ - 'id' => 'cached-model', - 'name' => 'Cached Model', - 'supportedCapabilities' => ['text_generation'], - 'supportedOptions' => [], - ]), - ]); - AiClient::setCache($cache); - - $this->mockHttpTransporter - ->expects($this->never()) - ->method('send'); - - $directory = new MockOpenAiCompatibleModelMetadataDirectory( - $this->mockHttpTransporter, - $this->mockRequestAuthentication, - null, - [], - true - ); - - $modelMetadata = $directory->getModelMetadata('cached-model'); - - $this->assertEquals('cached-model', $modelMetadata->getId()); - $this->assertEquals('Cached Model', $modelMetadata->getName()); - } - /** * Tests that cache keys are unique per child class. * diff --git a/tests/unit/Providers/ProviderRegistryTest.php b/tests/unit/Providers/ProviderRegistryTest.php index 214bb8ad..ff8197e6 100644 --- a/tests/unit/Providers/ProviderRegistryTest.php +++ b/tests/unit/Providers/ProviderRegistryTest.php @@ -6,7 +6,6 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; -use WordPress\AiClient\Providers\Http\Contracts\HttpTransporterInterface; use WordPress\AiClient\Providers\Http\Contracts\RequestAuthenticationInterface; use WordPress\AiClient\Providers\Http\DTO\ApiKeyRequestAuthentication; use WordPress\AiClient\Providers\Http\DTO\Request; @@ -21,8 +20,6 @@ use WordPress\AiClient\Tests\mocks\MockNoAuthProvider; use WordPress\AiClient\Tests\mocks\MockProvider; use WordPress\AiClient\Tests\mocks\MockProviderAvailability; -use WordPress\OpenAiAiProvider\Models\OpenAiTextGenerationModel; -use WordPress\OpenAiAiProvider\Provider\OpenAiProvider; /** * @covers \WordPress\AiClient\Providers\ProviderRegistry @@ -231,28 +228,6 @@ public function testGetProviderModelThrowsException(): void $this->registry->getProviderModel('mock', 'test-model', $modelConfig); } - /** - * Tests that explicit OpenAI model IDs instantiate without listing provider models. - * - * @return void - */ - public function testGetProviderModelWithExplicitOpenAiModelIdDoesNotListModels(): void - { - $httpTransporter = $this->createMock(HttpTransporterInterface::class); - $httpTransporter - ->expects($this->never()) - ->method('send'); - - $this->registry->setHttpTransporter($httpTransporter); - $this->registry->registerProvider(OpenAiProvider::class); - $this->registry->setProviderRequestAuthentication('openai', new ApiKeyRequestAuthentication('test-api-key')); - - $model = $this->registry->getProviderModel('openai', 'gpt-5.4', new ModelConfig([])); - - $this->assertInstanceOf(OpenAiTextGenerationModel::class, $model); - $this->assertEquals('gpt-5.4', $model->metadata()->getId()); - } - /** * Tests multiple provider registration. *