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