[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/php-ai-client/src/Messages/DTO/ -> Message.php (source)

   1  <?php
   2  
   3  declare (strict_types=1);
   4  namespace WordPress\AiClient\Messages\DTO;
   5  
   6  use WordPress\AiClient\Common\AbstractDataTransferObject;
   7  use WordPress\AiClient\Common\Exception\InvalidArgumentException;
   8  use WordPress\AiClient\Messages\Enums\MessageRoleEnum;
   9  /**
  10   * Represents a message in an AI conversation.
  11   *
  12   * Messages are the fundamental unit of communication with AI models,
  13   * containing a role and one or more parts with different content types.
  14   *
  15   * @since 0.1.0
  16   *
  17   * @phpstan-import-type MessagePartArrayShape from MessagePart
  18   *
  19   * @phpstan-type MessageArrayShape array{
  20   *     role: string,
  21   *     parts: array<MessagePartArrayShape>
  22   * }
  23   *
  24   * @extends AbstractDataTransferObject<MessageArrayShape>
  25   */
  26  class Message extends AbstractDataTransferObject
  27  {
  28      public const KEY_ROLE = 'role';
  29      public const KEY_PARTS = 'parts';
  30      /**
  31       * @var MessageRoleEnum The role of the message sender.
  32       */
  33      protected MessageRoleEnum $role;
  34      /**
  35       * @var MessagePart[] The parts that make up this message.
  36       */
  37      protected array $parts;
  38      /**
  39       * Constructor.
  40       *
  41       * @since 0.1.0
  42       *
  43       * @param MessageRoleEnum $role The role of the message sender.
  44       * @param MessagePart[] $parts The parts that make up this message.
  45       * @throws InvalidArgumentException If parts contain invalid content for the role.
  46       */
  47      public function __construct(MessageRoleEnum $role, array $parts)
  48      {
  49          $this->role = $role;
  50          $this->parts = $parts;
  51          $this->validateParts();
  52      }
  53      /**
  54       * Gets the role of the message sender.
  55       *
  56       * @since 0.1.0
  57       *
  58       * @return MessageRoleEnum The role.
  59       */
  60      public function getRole(): MessageRoleEnum
  61      {
  62          return $this->role;
  63      }
  64      /**
  65       * Gets the message parts.
  66       *
  67       * @since 0.1.0
  68       *
  69       * @return MessagePart[] The message parts.
  70       */
  71      public function getParts(): array
  72      {
  73          return $this->parts;
  74      }
  75      /**
  76       * Returns a new instance with the given part appended.
  77       *
  78       * @since 0.1.0
  79       *
  80       * @param MessagePart $part The part to append.
  81       * @return Message A new instance with the part appended.
  82       * @throws InvalidArgumentException If the part is invalid for the role.
  83       */
  84      public function withPart(\WordPress\AiClient\Messages\DTO\MessagePart $part): \WordPress\AiClient\Messages\DTO\Message
  85      {
  86          $newParts = $this->parts;
  87          $newParts[] = $part;
  88          return new \WordPress\AiClient\Messages\DTO\Message($this->role, $newParts);
  89      }
  90      /**
  91       * Validates that the message parts are appropriate for the message role.
  92       *
  93       * @since 0.1.0
  94       *
  95       * @return void
  96       * @throws InvalidArgumentException If validation fails.
  97       */
  98      private function validateParts(): void
  99      {
 100          foreach ($this->parts as $part) {
 101              $type = $part->getType();
 102              if ($this->role->isUser() && $type->isFunctionCall()) {
 103                  throw new InvalidArgumentException('User messages cannot contain function calls.');
 104              }
 105              if ($this->role->isModel() && $type->isFunctionResponse()) {
 106                  throw new InvalidArgumentException('Model messages cannot contain function responses.');
 107              }
 108          }
 109      }
 110      /**
 111       * {@inheritDoc}
 112       *
 113       * @since 0.1.0
 114       */
 115      public static function getJsonSchema(): array
 116      {
 117          return ['type' => 'object', 'properties' => [self::KEY_ROLE => ['type' => 'string', 'enum' => MessageRoleEnum::getValues(), 'description' => 'The role of the message sender.'], self::KEY_PARTS => ['type' => 'array', 'items' => \WordPress\AiClient\Messages\DTO\MessagePart::getJsonSchema(), 'minItems' => 1, 'description' => 'The parts that make up this message.']], 'required' => [self::KEY_ROLE, self::KEY_PARTS]];
 118      }
 119      /**
 120       * {@inheritDoc}
 121       *
 122       * @since 0.1.0
 123       *
 124       * @return MessageArrayShape
 125       */
 126      public function toArray(): array
 127      {
 128          return [self::KEY_ROLE => $this->role->value, self::KEY_PARTS => array_map(function (\WordPress\AiClient\Messages\DTO\MessagePart $part) {
 129              return $part->toArray();
 130          }, $this->parts)];
 131      }
 132      /**
 133       * {@inheritDoc}
 134       *
 135       * @since 0.1.0
 136       *
 137       * @return self The specific message class based on the role.
 138       */
 139      final public static function fromArray(array $array): self
 140      {
 141          static::validateFromArrayData($array, [self::KEY_ROLE, self::KEY_PARTS]);
 142          $role = MessageRoleEnum::from($array[self::KEY_ROLE]);
 143          $partsData = $array[self::KEY_PARTS];
 144          $parts = array_map(function (array $partData) {
 145              return \WordPress\AiClient\Messages\DTO\MessagePart::fromArray($partData);
 146          }, $partsData);
 147          // Determine which concrete class to instantiate based on role
 148          if ($role->isUser()) {
 149              return new \WordPress\AiClient\Messages\DTO\UserMessage($parts);
 150          } elseif ($role->isModel()) {
 151              return new \WordPress\AiClient\Messages\DTO\ModelMessage($parts);
 152          } else {
 153              // Only USER and MODEL roles are supported
 154              throw new InvalidArgumentException('Invalid message role: ' . $role->value);
 155          }
 156      }
 157      /**
 158       * Performs a deep clone of the message.
 159       *
 160       * This method ensures that message part objects are cloned to prevent
 161       * modifications to the cloned message from affecting the original.
 162       *
 163       * @since 0.4.2
 164       */
 165      public function __clone()
 166      {
 167          $clonedParts = [];
 168          foreach ($this->parts as $part) {
 169              $clonedParts[] = clone $part;
 170          }
 171          $this->parts = $clonedParts;
 172      }
 173  }


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