| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 declare (strict_types=1); 4 namespace WordPress\AiClient\Providers\Models\DTO; 5 6 use WordPress\AiClient\Common\AbstractDataTransferObject; 7 use WordPress\AiClient\Common\Exception\InvalidArgumentException; 8 use WordPress\AiClient\Messages\DTO\Message; 9 use WordPress\AiClient\Messages\Enums\ModalityEnum; 10 use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum; 11 use WordPress\AiClient\Providers\Models\Enums\OptionEnum; 12 /** 13 * Represents requirements that implementing code has for AI model selection. 14 * 15 * This class defines the capabilities and options that a model must support 16 * in order to be considered suitable for the implementing code's needs. 17 * 18 * @since 0.1.0 19 * 20 * @phpstan-import-type RequiredOptionArrayShape from RequiredOption 21 * 22 * @phpstan-type ModelRequirementsArrayShape array{ 23 * requiredCapabilities: list<string>, 24 * requiredOptions: list<RequiredOptionArrayShape> 25 * } 26 * 27 * @extends AbstractDataTransferObject<ModelRequirementsArrayShape> 28 */ 29 class ModelRequirements extends AbstractDataTransferObject 30 { 31 public const KEY_REQUIRED_CAPABILITIES = 'requiredCapabilities'; 32 public const KEY_REQUIRED_OPTIONS = 'requiredOptions'; 33 /** 34 * @var list<CapabilityEnum> The capabilities that the model must support. 35 */ 36 protected array $requiredCapabilities; 37 /** 38 * @var list<RequiredOption> The options that the model must support with specific values. 39 */ 40 protected array $requiredOptions; 41 /** 42 * Constructor. 43 * 44 * @since 0.1.0 45 * 46 * @param list<CapabilityEnum> $requiredCapabilities The capabilities that the model must support. 47 * @param list<RequiredOption> $requiredOptions The options that the model must support with specific values. 48 * 49 * @throws InvalidArgumentException If arrays are not lists. 50 */ 51 public function __construct(array $requiredCapabilities, array $requiredOptions) 52 { 53 if (!array_is_list($requiredCapabilities)) { 54 throw new InvalidArgumentException('Required capabilities must be a list array.'); 55 } 56 if (!array_is_list($requiredOptions)) { 57 throw new InvalidArgumentException('Required options must be a list array.'); 58 } 59 $this->requiredCapabilities = $requiredCapabilities; 60 $this->requiredOptions = $requiredOptions; 61 } 62 /** 63 * Gets the capabilities that the model must support. 64 * 65 * @since 0.1.0 66 * 67 * @return list<CapabilityEnum> The required capabilities. 68 */ 69 public function getRequiredCapabilities(): array 70 { 71 return $this->requiredCapabilities; 72 } 73 /** 74 * Gets the options that the model must support with specific values. 75 * 76 * @since 0.1.0 77 * 78 * @return list<RequiredOption> The required options. 79 */ 80 public function getRequiredOptions(): array 81 { 82 return $this->requiredOptions; 83 } 84 /** 85 * Checks whether the given model metadata meets these requirements. 86 * 87 * @since 0.2.0 88 * 89 * @param ModelMetadata $metadata The model metadata to check against. 90 * @return bool True if the model meets all requirements, false otherwise. 91 */ 92 public function areMetBy(\WordPress\AiClient\Providers\Models\DTO\ModelMetadata $metadata): bool 93 { 94 // Create lookup maps for better performance (instead of nested foreach loops) 95 $capabilitiesMap = []; 96 foreach ($metadata->getSupportedCapabilities() as $capability) { 97 $capabilitiesMap[$capability->value] = $capability; 98 } 99 $optionsMap = []; 100 foreach ($metadata->getSupportedOptions() as $option) { 101 $optionsMap[$option->getName()->value] = $option; 102 } 103 // Check if all required capabilities are supported using map lookup 104 foreach ($this->requiredCapabilities as $requiredCapability) { 105 if (!isset($capabilitiesMap[$requiredCapability->value])) { 106 return \false; 107 } 108 } 109 // Check if all required options are supported with the specified values 110 foreach ($this->requiredOptions as $requiredOption) { 111 // Use map lookup instead of linear search 112 if (!isset($optionsMap[$requiredOption->getName()->value])) { 113 return \false; 114 } 115 $supportedOption = $optionsMap[$requiredOption->getName()->value]; 116 // Check if the required value is supported by this option 117 if (!$supportedOption->isSupportedValue($requiredOption->getValue())) { 118 return \false; 119 } 120 } 121 return \true; 122 } 123 /** 124 * Creates ModelRequirements from prompt data and model configuration. 125 * 126 * @since 0.2.0 127 * 128 * @param CapabilityEnum $capability The capability the model must support. 129 * @param list<Message> $messages The messages in the conversation. 130 * @param ModelConfig $modelConfig The model configuration. 131 * @return self The created requirements. 132 */ 133 public static function fromPromptData(CapabilityEnum $capability, array $messages, \WordPress\AiClient\Providers\Models\DTO\ModelConfig $modelConfig): self 134 { 135 // Start with base capability 136 $capabilities = [$capability]; 137 $inputModalities = []; 138 // Check if we have chat history (multiple messages) 139 if (count($messages) > 1) { 140 $capabilities[] = CapabilityEnum::chatHistory(); 141 } 142 // Analyze all messages to determine required input modalities 143 $hasFunctionMessageParts = \false; 144 foreach ($messages as $message) { 145 foreach ($message->getParts() as $part) { 146 // Check for text input 147 if ($part->getType()->isText()) { 148 $inputModalities[] = ModalityEnum::text(); 149 } 150 // Check for file inputs 151 if ($part->getType()->isFile()) { 152 $file = $part->getFile(); 153 if ($file !== null) { 154 if ($file->isImage()) { 155 $inputModalities[] = ModalityEnum::image(); 156 } elseif ($file->isAudio()) { 157 $inputModalities[] = ModalityEnum::audio(); 158 } elseif ($file->isVideo()) { 159 $inputModalities[] = ModalityEnum::video(); 160 } elseif ($file->isDocument() || $file->isText()) { 161 $inputModalities[] = ModalityEnum::document(); 162 } 163 } 164 } 165 // Check for function calls/responses (these might require special capabilities) 166 if ($part->getType()->isFunctionCall() || $part->getType()->isFunctionResponse()) { 167 $hasFunctionMessageParts = \true; 168 } 169 } 170 } 171 // Convert ModelConfig to RequiredOptions 172 $requiredOptions = self::toRequiredOptions($modelConfig); 173 // Add additional options based on message analysis 174 if ($hasFunctionMessageParts) { 175 $requiredOptions = self::includeInRequiredOptions($requiredOptions, new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::functionDeclarations(), \true)); 176 } 177 // Add input modalities if we have any inputs 178 if (!empty($inputModalities)) { 179 // Remove duplicates 180 $inputModalities = array_unique($inputModalities, \SORT_REGULAR); 181 $requiredOptions = self::includeInRequiredOptions($requiredOptions, new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::inputModalities(), array_values($inputModalities))); 182 } 183 // Step 6: Return new ModelRequirements 184 return new self($capabilities, $requiredOptions); 185 } 186 /** 187 * Converts ModelConfig to an array of RequiredOptions. 188 * 189 * @since 0.2.0 190 * 191 * @param ModelConfig $modelConfig The model configuration. 192 * @return list<RequiredOption> The required options. 193 */ 194 private static function toRequiredOptions(\WordPress\AiClient\Providers\Models\DTO\ModelConfig $modelConfig): array 195 { 196 $requiredOptions = []; 197 // Map properties that have corresponding OptionEnum values 198 if ($modelConfig->getOutputModalities() !== null) { 199 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputModalities(), $modelConfig->getOutputModalities()); 200 } 201 if ($modelConfig->getSystemInstruction() !== null) { 202 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::systemInstruction(), $modelConfig->getSystemInstruction()); 203 } 204 if ($modelConfig->getCandidateCount() !== null) { 205 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::candidateCount(), $modelConfig->getCandidateCount()); 206 } 207 if ($modelConfig->getMaxTokens() !== null) { 208 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::maxTokens(), $modelConfig->getMaxTokens()); 209 } 210 if ($modelConfig->getTemperature() !== null) { 211 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::temperature(), $modelConfig->getTemperature()); 212 } 213 if ($modelConfig->getTopP() !== null) { 214 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::topP(), $modelConfig->getTopP()); 215 } 216 if ($modelConfig->getTopK() !== null) { 217 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::topK(), $modelConfig->getTopK()); 218 } 219 if ($modelConfig->getOutputMimeType() !== null) { 220 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputMimeType(), $modelConfig->getOutputMimeType()); 221 } 222 if ($modelConfig->getOutputSchema() !== null) { 223 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputSchema(), $modelConfig->getOutputSchema()); 224 } 225 // Handle properties without OptionEnum values as custom options 226 if ($modelConfig->getStopSequences() !== null) { 227 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::stopSequences(), $modelConfig->getStopSequences()); 228 } 229 if ($modelConfig->getPresencePenalty() !== null) { 230 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::presencePenalty(), $modelConfig->getPresencePenalty()); 231 } 232 if ($modelConfig->getFrequencyPenalty() !== null) { 233 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::frequencyPenalty(), $modelConfig->getFrequencyPenalty()); 234 } 235 if ($modelConfig->getLogprobs() !== null) { 236 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::logprobs(), $modelConfig->getLogprobs()); 237 } 238 if ($modelConfig->getTopLogprobs() !== null) { 239 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::topLogprobs(), $modelConfig->getTopLogprobs()); 240 } 241 if ($modelConfig->getFunctionDeclarations() !== null) { 242 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::functionDeclarations(), \true); 243 } 244 if ($modelConfig->getWebSearch() !== null) { 245 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::webSearch(), \true); 246 } 247 if ($modelConfig->getOutputFileType() !== null) { 248 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputFileType(), $modelConfig->getOutputFileType()); 249 } 250 if ($modelConfig->getOutputMediaOrientation() !== null) { 251 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputMediaOrientation(), $modelConfig->getOutputMediaOrientation()); 252 } 253 if ($modelConfig->getOutputMediaAspectRatio() !== null) { 254 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputMediaAspectRatio(), $modelConfig->getOutputMediaAspectRatio()); 255 } 256 // Add custom options as individual RequiredOptions 257 foreach ($modelConfig->getCustomOptions() as $key => $value) { 258 $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::customOptions(), [$key => $value]); 259 } 260 return $requiredOptions; 261 } 262 /** 263 * Includes a RequiredOption in the array, ensuring no duplicates based on option name. 264 * 265 * @since 0.2.0 266 * 267 * @param list<RequiredOption> $requiredOptions The existing required options. 268 * @param RequiredOption $newOption The new option to include. 269 * @return list<RequiredOption> The updated required options array. 270 */ 271 private static function includeInRequiredOptions(array $requiredOptions, \WordPress\AiClient\Providers\Models\DTO\RequiredOption $newOption): array 272 { 273 // Check if we already have this option name 274 foreach ($requiredOptions as $index => $existingOption) { 275 if ($existingOption->getName()->equals($newOption->getName())) { 276 // Replace existing option with new one 277 $requiredOptions[$index] = $newOption; 278 return $requiredOptions; 279 } 280 } 281 // Option not found, add it 282 $requiredOptions[] = $newOption; 283 return $requiredOptions; 284 } 285 /** 286 * {@inheritDoc} 287 * 288 * @since 0.1.0 289 */ 290 public static function getJsonSchema(): array 291 { 292 return ['type' => 'object', 'properties' => [self::KEY_REQUIRED_CAPABILITIES => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => CapabilityEnum::getValues()], 'description' => 'The capabilities that the model must support.'], self::KEY_REQUIRED_OPTIONS => ['type' => 'array', 'items' => \WordPress\AiClient\Providers\Models\DTO\RequiredOption::getJsonSchema(), 'description' => 'The options that the model must support with specific values.']], 'required' => [self::KEY_REQUIRED_CAPABILITIES, self::KEY_REQUIRED_OPTIONS]]; 293 } 294 /** 295 * {@inheritDoc} 296 * 297 * @since 0.1.0 298 * 299 * @return ModelRequirementsArrayShape 300 */ 301 public function toArray(): array 302 { 303 return [self::KEY_REQUIRED_CAPABILITIES => array_map(static fn(CapabilityEnum $capability): string => $capability->value, $this->requiredCapabilities), self::KEY_REQUIRED_OPTIONS => array_map(static fn(\WordPress\AiClient\Providers\Models\DTO\RequiredOption $option): array => $option->toArray(), $this->requiredOptions)]; 304 } 305 /** 306 * {@inheritDoc} 307 * 308 * @since 0.1.0 309 */ 310 public static function fromArray(array $array): self 311 { 312 static::validateFromArrayData($array, [self::KEY_REQUIRED_CAPABILITIES, self::KEY_REQUIRED_OPTIONS]); 313 return new self(array_map(static fn(string $capability): CapabilityEnum => CapabilityEnum::from($capability), $array[self::KEY_REQUIRED_CAPABILITIES]), array_map(static fn(array $optionData): \WordPress\AiClient\Providers\Models\DTO\RequiredOption => \WordPress\AiClient\Providers\Models\DTO\RequiredOption::fromArray($optionData), $array[self::KEY_REQUIRED_OPTIONS])); 314 } 315 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Jun 13 09:38:55 2026 | Cross-referenced by PHPXref |