[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/php-ai-client/src/Providers/Models/DTO/ -> ModelRequirements.php (source)

   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  }


Generated : Sat Jun 13 09:38:55 2026 Cross-referenced by PHPXref