diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 6f360233..76782583 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -340,6 +340,7 @@ direction LR +convertTextToSpeeches(?int $candidateCount) File[] +generateSpeech() File +generateSpeeches(?int $candidateCount) File[] + +isSupported(?CapabilityEnum $capability) bool +isSupportedForTextGeneration() bool +isSupportedForImageGeneration() bool +isSupportedForTextToSpeechConversion() bool diff --git a/src/Builders/PromptBuilder.php b/src/Builders/PromptBuilder.php index 758aeeda..84414996 100644 --- a/src/Builders/PromptBuilder.php +++ b/src/Builders/PromptBuilder.php @@ -492,7 +492,7 @@ public function usingWebSearch(WebSearch $webSearch): self /** * Sets the request options for HTTP transport. * - * @since n.e.x.t + * @since 0.3.0 * * @param RequestOptions $requestOptions The request options. * @return self @@ -676,19 +676,31 @@ private function inferCapabilityFromModelInterfaces(ModelInterface $model): ?Cap * Checks if the current prompt is supported by the selected model. * * @since 0.1.0 + * @since 0.3.0 Method visibility changed to public. * - * @param CapabilityEnum|null $intendedCapability Optional capability to check support for. + * @param CapabilityEnum|null $capability Optional capability to check support for. * @return bool True if supported, false otherwise. */ - private function isSupported(?CapabilityEnum $intendedCapability = null): bool + public function isSupported(?CapabilityEnum $capability = null): bool { // If no intended capability provided, infer from output modalities - if ($intendedCapability === null) { - $intendedCapability = $this->inferCapabilityFromOutputModalities(); + if ($capability === null) { + // First try to infer from a specific model if one is set + if ($this->model !== null) { + $inferredCapability = $this->inferCapabilityFromModelInterfaces($this->model); + if ($inferredCapability !== null) { + $capability = $inferredCapability; + } + } + + // If still no capability, infer from output modalities + if ($capability === null) { + $capability = $this->inferCapabilityFromOutputModalities(); + } } // Build requirements with the specified capability - $requirements = ModelRequirements::fromPromptData($intendedCapability, $this->messages, $this->modelConfig); + $requirements = ModelRequirements::fromPromptData($capability, $this->messages, $this->modelConfig); // If the model has been set, check if it meets the requirements if ($this->model !== null) { @@ -1192,7 +1204,7 @@ private function getConfiguredModel(CapabilityEnum $capability): ModelInterface * * Request options are only applicable to API-based models that make HTTP requests. * - * @since n.e.x.t + * @since 0.3.0 * * @param ModelInterface $model The model to bind request options to. * @return void diff --git a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php index e1a93e5e..c2124c66 100644 --- a/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php +++ b/src/Providers/ApiBasedImplementation/AbstractApiBasedModel.php @@ -108,7 +108,7 @@ final public function getConfig(): ModelConfig /** * {@inheritDoc} * - * @since n.e.x.t + * @since 0.3.0 */ final public function setRequestOptions(RequestOptions $requestOptions): void { @@ -118,7 +118,7 @@ final public function setRequestOptions(RequestOptions $requestOptions): void /** * {@inheritDoc} * - * @since n.e.x.t + * @since 0.3.0 */ final public function getRequestOptions(): ?RequestOptions { diff --git a/src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php b/src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php index e7690365..73fa219c 100644 --- a/src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php +++ b/src/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.php @@ -13,14 +13,14 @@ * This interface extends ModelInterface to add request options support * for models that communicate with external APIs via HTTP. * - * @since n.e.x.t + * @since 0.3.0 */ interface ApiBasedModelInterface extends ModelInterface { /** * Sets the request options for HTTP transport. * - * @since n.e.x.t + * @since 0.3.0 * * @param RequestOptions $requestOptions The request options to use. * @return void @@ -30,7 +30,7 @@ public function setRequestOptions(RequestOptions $requestOptions): void; /** * Gets the request options for HTTP transport. * - * @since n.e.x.t + * @since 0.3.0 * * @return RequestOptions|null The request options, or null if not set. */ diff --git a/tests/unit/Builders/PromptBuilderTest.php b/tests/unit/Builders/PromptBuilderTest.php index de23054a..baba23d6 100644 --- a/tests/unit/Builders/PromptBuilderTest.php +++ b/tests/unit/Builders/PromptBuilderTest.php @@ -3390,4 +3390,123 @@ public function testMethodChainingWithNewMethods(): void $this->assertTrue($config->getLogprobs()); $this->assertEquals(3, $config->getTopLogprobs()); } + + /** + * Tests isSupported method with explicit capability. + * + * @return void + */ + public function testIsSupportedWithExplicitCapability(): void + { + $builder = new PromptBuilder($this->registry, 'Test prompt'); + + // Mock registry to return a model supporting text generation + $this->registry->method('findModelsMetadataForSupport') + ->willReturn([$this->createMock(ProviderModelsMetadata::class)]); + + $this->assertTrue($builder->isSupported(CapabilityEnum::textGeneration())); + } + + /** + * Tests isSupported method with inferred capability from output modalities. + * + * @return void + */ + public function testIsSupportedWithInferredCapability(): void + { + $builder = new PromptBuilder($this->registry, 'Test prompt'); + $builder->asOutputModalities(ModalityEnum::image()); + + // Mock registry to return a model supporting image generation + $this->registry->method('findModelsMetadataForSupport') + ->willReturn([$this->createMock(ProviderModelsMetadata::class)]); + + // Should infer image generation capability + $this->assertTrue($builder->isSupported()); + } + + /** + * Tests isSupported method with inferred capability from model interfaces. + * + * @return void + */ + public function testIsSupportedWithInferredCapabilityFromModel(): void + { + $metadata = $this->createMock(ModelMetadata::class); + $metadata->method('getId')->willReturn('test-model'); + $metadata->method('getSupportedCapabilities')->willReturn([ + CapabilityEnum::textGeneration() + ]); + $metadata->method('getSupportedOptions')->willReturn([ + new SupportedOption(OptionEnum::inputModalities(), [ + [ModalityEnum::text()] + ]) + ]); + + $result = new GenerativeAiResult('test-id', [ + new Candidate( + new ModelMessage([new MessagePart('Test')]), + FinishReasonEnum::stop() + ) + ], new TokenUsage(10, 5, 15), $this->createTestProviderMetadata(), $this->createTestTextModelMetadata()); + + $model = $this->createMockTextGenerationModel($result, $metadata); + + $builder = new PromptBuilder($this->registry, 'Test prompt'); + $builder->usingModel($model); + + // Should infer text generation capability from the model interface + $this->assertTrue($builder->isSupported()); + } + + /** + * Tests isSupported method when a model is explicitly set. + * + * @return void + */ + public function testIsSupportedWithModelSet(): void + { + $metadata = $this->createMock(ModelMetadata::class); + $metadata->method('getId')->willReturn('text-model'); + $metadata->method('getSupportedCapabilities')->willReturn([ + CapabilityEnum::textGeneration() + ]); + // Mock getSupportedOptions to return required options + $metadata->method('getSupportedOptions')->willReturn([ + new SupportedOption(OptionEnum::inputModalities(), [ + [ModalityEnum::text()] + ]) + ]); + + $result = new GenerativeAiResult('test-id', [ + new Candidate( + new ModelMessage([new MessagePart('Test')]), + FinishReasonEnum::stop() + ) + ], new TokenUsage(10, 5, 15), $this->createTestProviderMetadata(), $this->createTestTextModelMetadata()); + + $model = $this->createMockTextGenerationModel($result, $metadata); + + $builder = new PromptBuilder($this->registry, 'Test prompt'); + $builder->usingModel($model); + + $this->assertTrue($builder->isSupported(CapabilityEnum::textGeneration())); + $this->assertFalse($builder->isSupported(CapabilityEnum::imageGeneration())); + } + + /** + * Tests isSupported method when no models support the requirements. + * + * @return void + */ + public function testIsSupportedWithNoSupport(): void + { + $builder = new PromptBuilder($this->registry, 'Test prompt'); + + // Mock registry to return no models + $this->registry->method('findModelsMetadataForSupport') + ->willReturn([]); + + $this->assertFalse($builder->isSupported(CapabilityEnum::textGeneration())); + } }