| [ 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\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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Jun 13 09:38:55 2026 | Cross-referenced by PHPXref |