1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus MCP SDK package.
7: *
8: * (c) 2026 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\Mcp\Core\Schema\ContentBlock;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\Annotations;
18: use Nexus\Mcp\Core\Schema\Arrayable;
19: use Nexus\Mcp\Core\Schema\ContentBlock;
20: use Nexus\Mcp\Core\Schema\MetaObject;
21: use Nexus\Mcp\Core\Schema\Sampling\SamplingMessageContentBlock;
22:
23: /**
24: * Text provided to or from an LLM.
25: *
26: * @implements Arrayable<array{
27: * text: string,
28: * type: 'text',
29: * annotations?: template-type<Annotations, Arrayable, 'T'>,
30: * _meta?: template-type<MetaObject, Arrayable, 'T'>,
31: * }>
32: *
33: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#textcontent
34: */
35: final readonly class TextContent implements Arrayable, ContentBlock, SamplingMessageContentBlock
36: {
37: public const string TYPE = 'text';
38:
39: public function __construct(
40: public string $text,
41: public Annotations $annotations = new Annotations(),
42: public MetaObject $meta = new MetaObject(),
43: ) {
44: }
45:
46: /**
47: * @param array<string, mixed> $data
48: */
49: #[\Override]
50: public static function fromArray(array $data): static
51: {
52: Assert::that($data)->hasOffset('type', 'text content missing the required "type" key.');
53: $type = $data['type'];
54: Assert::that($type)->isIdentical(self::TYPE, 'text content "type" must be {other}, {value} given.');
55:
56: Assert::that($data)->hasOffset('text', 'text content missing the required "text" key.');
57: $text = $data['text'];
58: Assert::that($text)->isString('text content "text" must be a string, {type} given.');
59:
60: $annotations = new Annotations();
61:
62: if (\array_key_exists('annotations', $data)) {
63: Assert::that($data['annotations'])
64: ->isArray('text content "annotations" must be an object, {type} given.')
65: ->isMap('text content "annotations" must be a string-keyed object.')
66: ;
67: $annotations = Annotations::fromArray($data['annotations']);
68: }
69:
70: $meta = new MetaObject();
71:
72: if (\array_key_exists('_meta', $data)) {
73: Assert::that($data['_meta'])
74: ->isArray('text content "_meta" must be an object, {type} given.')
75: ->isMap('text content "_meta" must be a string-keyed object.')
76: ;
77: $meta = MetaObject::fromArray($data['_meta']);
78: }
79:
80: return new self($text, $annotations, $meta);
81: }
82:
83: #[\Override]
84: public function toArray(): array
85: {
86: $data = [
87: 'text' => $this->text,
88: 'type' => self::TYPE,
89: ];
90:
91: $annotations = $this->annotations->toArray();
92:
93: if ([] !== $annotations) {
94: $data['annotations'] = $annotations;
95: }
96:
97: $meta = $this->meta->toArray();
98:
99: if ([] !== $meta) {
100: $data['_meta'] = $meta;
101: }
102:
103: return $data;
104: }
105:
106: #[\Override]
107: public function jsonSerialize(): array
108: {
109: return $this->toArray();
110: }
111: }
112: