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