Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Providers/Models/DTO/ModelConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -1068,13 +1068,13 @@ public function toRequiredOptions(): array
}

if ($this->outputFileType !== null) {
$requiredOptions[] = new RequiredOption(OptionEnum::outputFileType(), $this->outputFileType->value);
$requiredOptions[] = new RequiredOption(OptionEnum::outputFileType(), $this->outputFileType);
}

if ($this->outputMediaOrientation !== null) {
$requiredOptions[] = new RequiredOption(
OptionEnum::outputMediaOrientation(),
$this->outputMediaOrientation->value
$this->outputMediaOrientation
);
}

Expand Down
243 changes: 243 additions & 0 deletions tests/unit/Providers/Models/DTO/ModelConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use WordPress\AiClient\Files\Enums\MediaOrientationEnum;
use WordPress\AiClient\Messages\Enums\ModalityEnum;
use WordPress\AiClient\Providers\Models\DTO\ModelConfig;
use WordPress\AiClient\Providers\Models\Enums\OptionEnum;
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
use WordPress\AiClient\Tools\DTO\WebSearch;

Expand Down Expand Up @@ -703,4 +704,246 @@ public function testSetCustomOption(): void
$restored = ModelConfig::fromArray($array);
$this->assertEquals($customOptions, $restored->getCustomOptions());
}

/**
* Tests toRequiredOptions method with all properties.
*
* @return void
*/
public function testToRequiredOptionsWithAllProperties(): void
{
$config = new ModelConfig();

// Set all properties that map to RequiredOptions
$config->setOutputModalities([ModalityEnum::text(), ModalityEnum::image()]);
$config->setSystemInstruction('Be helpful');
$config->setCandidateCount(2);
$config->setMaxTokens(1000);
$config->setTemperature(0.7);
$config->setTopP(0.9);
$config->setTopK(40);
$config->setStopSequences(['STOP', 'END']);
$config->setPresencePenalty(0.5);
$config->setFrequencyPenalty(0.3);
$config->setLogprobs(true);
$config->setTopLogprobs(5);
$config->setFunctionDeclarations([$this->createSampleFunctionDeclaration()]);
$config->setWebSearch($this->createSampleWebSearch());
$config->setOutputFileType(FileTypeEnum::inline());
$config->setOutputMimeType('application/json');
$config->setOutputSchema(['type' => 'object']);
$config->setOutputMediaOrientation(MediaOrientationEnum::landscape());
$config->setOutputMediaAspectRatio('16:9');
$config->setCustomOptions(['key1' => 'value1', 'key2' => 'value2']);

$requiredOptions = $config->toRequiredOptions();

$this->assertIsArray($requiredOptions);
$this->assertNotEmpty($requiredOptions);

// Helper function to find option by name
/**
* @param list<\WordPress\AiClient\Providers\Models\DTO\RequiredOption> $options
* @param OptionEnum $name
* @return \WordPress\AiClient\Providers\Models\DTO\RequiredOption|null
*/
$findOption = function (
array $options,
OptionEnum $name
): ?\WordPress\AiClient\Providers\Models\DTO\RequiredOption {
foreach ($options as $option) {
if ($option->getName()->equals($name)) {
return $option;
}
}
return null;
};

// Test output modalities
$outputModalitiesOption = $findOption($requiredOptions, OptionEnum::outputModalities());
$this->assertNotNull($outputModalitiesOption);
$this->assertEquals([ModalityEnum::text(), ModalityEnum::image()], $outputModalitiesOption->getValue());

// Test system instruction
$systemInstructionOption = $findOption($requiredOptions, OptionEnum::systemInstruction());
$this->assertNotNull($systemInstructionOption);
$this->assertEquals('Be helpful', $systemInstructionOption->getValue());

// Test candidate count
$candidateCountOption = $findOption($requiredOptions, OptionEnum::candidateCount());
$this->assertNotNull($candidateCountOption);
$this->assertEquals(2, $candidateCountOption->getValue());

// Test max tokens
$maxTokensOption = $findOption($requiredOptions, OptionEnum::maxTokens());
$this->assertNotNull($maxTokensOption);
$this->assertEquals(1000, $maxTokensOption->getValue());

// Test temperature
$temperatureOption = $findOption($requiredOptions, OptionEnum::temperature());
$this->assertNotNull($temperatureOption);
$this->assertEquals(0.7, $temperatureOption->getValue());

// Test top-p
$topPOption = $findOption($requiredOptions, OptionEnum::topP());
$this->assertNotNull($topPOption);
$this->assertEquals(0.9, $topPOption->getValue());

// Test top-k
$topKOption = $findOption($requiredOptions, OptionEnum::topK());
$this->assertNotNull($topKOption);
$this->assertEquals(40, $topKOption->getValue());

// Test stop sequences
$stopSequencesOption = $findOption($requiredOptions, OptionEnum::stopSequences());
$this->assertNotNull($stopSequencesOption);
$this->assertEquals(['STOP', 'END'], $stopSequencesOption->getValue());

// Test presence penalty
$presencePenaltyOption = $findOption($requiredOptions, OptionEnum::presencePenalty());
$this->assertNotNull($presencePenaltyOption);
$this->assertEquals(0.5, $presencePenaltyOption->getValue());

// Test frequency penalty
$frequencyPenaltyOption = $findOption($requiredOptions, OptionEnum::frequencyPenalty());
$this->assertNotNull($frequencyPenaltyOption);
$this->assertEquals(0.3, $frequencyPenaltyOption->getValue());

// Test logprobs
$logprobsOption = $findOption($requiredOptions, OptionEnum::logprobs());
$this->assertNotNull($logprobsOption);
$this->assertTrue($logprobsOption->getValue());

// Test top logprobs
$topLogprobsOption = $findOption($requiredOptions, OptionEnum::topLogprobs());
$this->assertNotNull($topLogprobsOption);
$this->assertEquals(5, $topLogprobsOption->getValue());

// Test function declarations (should be boolean true)
$functionDeclarationsOption = $findOption($requiredOptions, OptionEnum::functionDeclarations());
$this->assertNotNull($functionDeclarationsOption);
$this->assertTrue($functionDeclarationsOption->getValue());

// Test web search (should be boolean true)
$webSearchOption = $findOption($requiredOptions, OptionEnum::webSearch());
$this->assertNotNull($webSearchOption);
$this->assertTrue($webSearchOption->getValue());

// Test output file type - IMPORTANT: Should be the enum object, not the string value
$outputFileTypeOption = $findOption($requiredOptions, OptionEnum::outputFileType());
$this->assertNotNull($outputFileTypeOption);
$this->assertInstanceOf(FileTypeEnum::class, $outputFileTypeOption->getValue());
$this->assertSame(FileTypeEnum::inline(), $outputFileTypeOption->getValue());

// Test output MIME type
$outputMimeTypeOption = $findOption($requiredOptions, OptionEnum::outputMimeType());
$this->assertNotNull($outputMimeTypeOption);
$this->assertEquals('application/json', $outputMimeTypeOption->getValue());

// Test output schema
$outputSchemaOption = $findOption($requiredOptions, OptionEnum::outputSchema());
$this->assertNotNull($outputSchemaOption);
$this->assertEquals(['type' => 'object'], $outputSchemaOption->getValue());

// Test output media orientation - IMPORTANT: Should be the enum object, not the string value
$outputMediaOrientationOption = $findOption($requiredOptions, OptionEnum::outputMediaOrientation());
$this->assertNotNull($outputMediaOrientationOption);
$this->assertInstanceOf(MediaOrientationEnum::class, $outputMediaOrientationOption->getValue());
$this->assertSame(MediaOrientationEnum::landscape(), $outputMediaOrientationOption->getValue());

// Test output media aspect ratio
$outputMediaAspectRatioOption = $findOption($requiredOptions, OptionEnum::outputMediaAspectRatio());
$this->assertNotNull($outputMediaAspectRatioOption);
$this->assertEquals('16:9', $outputMediaAspectRatioOption->getValue());

// Test custom options - each custom option should be a separate RequiredOption
$customOptions = array_filter($requiredOptions, function ($option) {
return $option->getName()->equals(OptionEnum::customOptions());
});
$this->assertCount(2, $customOptions); // We set 2 custom options

// Verify custom option values
$customOptionValues = array_map(function ($option) {
return $option->getValue();
}, $customOptions);
$this->assertContains(['key1' => 'value1'], $customOptionValues);
$this->assertContains(['key2' => 'value2'], $customOptionValues);
}

/**
* Tests toRequiredOptions method with no properties set.
*
* @return void
*/
public function testToRequiredOptionsWithNoProperties(): void
{
$config = new ModelConfig();
$requiredOptions = $config->toRequiredOptions();

$this->assertIsArray($requiredOptions);
$this->assertEmpty($requiredOptions);
}

/**
* Tests toRequiredOptions method with partial properties.
*
* @return void
*/
public function testToRequiredOptionsWithPartialProperties(): void
{
$config = new ModelConfig();

// Only set a few properties
$config->setTemperature(0.8);
$config->setMaxTokens(500);
$config->setOutputFileType(FileTypeEnum::remote());
$config->setOutputMediaOrientation(MediaOrientationEnum::portrait());

$requiredOptions = $config->toRequiredOptions();

$this->assertIsArray($requiredOptions);
$this->assertCount(4, $requiredOptions);

// Helper function to find option by name
/**
* @param list<\WordPress\AiClient\Providers\Models\DTO\RequiredOption> $options
* @param OptionEnum $name
* @return \WordPress\AiClient\Providers\Models\DTO\RequiredOption|null
*/
$findOption = function (
array $options,
OptionEnum $name
): ?\WordPress\AiClient\Providers\Models\DTO\RequiredOption {
foreach ($options as $option) {
if ($option->getName()->equals($name)) {
return $option;
}
}
return null;
};

// Test temperature
$temperatureOption = $findOption($requiredOptions, OptionEnum::temperature());
$this->assertNotNull($temperatureOption);
$this->assertEquals(0.8, $temperatureOption->getValue());

// Test max tokens
$maxTokensOption = $findOption($requiredOptions, OptionEnum::maxTokens());
$this->assertNotNull($maxTokensOption);
$this->assertEquals(500, $maxTokensOption->getValue());

// Test output file type - Should be the enum object
$outputFileTypeOption = $findOption($requiredOptions, OptionEnum::outputFileType());
$this->assertNotNull($outputFileTypeOption);
$this->assertInstanceOf(FileTypeEnum::class, $outputFileTypeOption->getValue());
$this->assertSame(FileTypeEnum::remote(), $outputFileTypeOption->getValue());
$this->assertTrue($outputFileTypeOption->getValue()->isRemote());

// Test output media orientation - Should be the enum object
$outputMediaOrientationOption = $findOption($requiredOptions, OptionEnum::outputMediaOrientation());
$this->assertNotNull($outputMediaOrientationOption);
$this->assertInstanceOf(MediaOrientationEnum::class, $outputMediaOrientationOption->getValue());
$this->assertSame(MediaOrientationEnum::portrait(), $outputMediaOrientationOption->getValue());
$this->assertTrue($outputMediaOrientationOption->getValue()->isPortrait());
}
}