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:
22: /**
23: * Text provided to or from an LLM.
24: *
25: * @implements Arrayable<array{
26: * text: string,
27: * type: 'text',
28: * annotations?: template-type<Annotations, Arrayable, 'T'>,
29: * _meta?: template-type<MetaObject, Arrayable, 'T'>,
30: * }>
31: *
32: * @see https://modelcontextprotocol.io/specification/draft/schema#textcontent
33: */
34: final readonly class TextContent implements Arrayable, ContentBlock
35: {
36: public const string TYPE = 'text';
37:
38: public function __construct(
39: public string $text,
40: public Annotations $annotations = new Annotations(),
41: public MetaObject $meta = new MetaObject(),
42: ) {
43: }
44:
45: #[\Override]
46: public static function fromArray(array $data): static
47: {
48: Assert::that($data)->hasOffset('type', 'text content is missing the required "type" key.');
49: $type = $data['type'];
50: Assert::that($type)->isIdentical(self::TYPE, 'text content "type" must be {other}, {value} given.');
51:
52: Assert::that($data)->hasOffset('text', 'text content is missing the required "text" key.');
53: $text = $data['text'];
54: Assert::that($text)->isString('text content "text" must be a string, {type} given.');
55:
56: $annotations = new Annotations();
57:
58: if (\array_key_exists('annotations', $data)) {
59: Assert::that($data['annotations'])
60: ->isArray('text content "annotations" must be an object, {type} given.')
61: ->isMap('text content "annotations" must be a string-keyed object.')
62: ;
63: $annotations = Annotations::fromArray($data['annotations']);
64: }
65:
66: $meta = new MetaObject();
67:
68: if (\array_key_exists('_meta', $data)) {
69: Assert::that($data['_meta'])
70: ->isArray('text content "_meta" must be an object, {type} given.')
71: ->isMap('text content "_meta" must be a string-keyed object.')
72: ;
73: $meta = MetaObject::fromArray($data['_meta']);
74: }
75:
76: return new self(text: $text, annotations: $annotations, meta: $meta);
77: }
78:
79: #[\Override]
80: public function toArray(): array
81: {
82: $data = [
83: 'text' => $this->text,
84: 'type' => self::TYPE,
85: ];
86:
87: $annotations = $this->annotations->toArray();
88:
89: if ([] !== $annotations) {
90: $data['annotations'] = $annotations;
91: }
92:
93: $meta = $this->meta->toArray();
94:
95: if ([] !== $meta) {
96: $data['_meta'] = $meta;
97: }
98:
99: return $data;
100: }
101:
102: #[\Override]
103: public function jsonSerialize(): array
104: {
105: return $this->toArray();
106: }
107: }
108: