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: * 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<MetaObject, Arrayable, 'T'>,
32: * }>
33: *
34: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#audiocontent
35: */
36: final readonly class AudioContent implements Arrayable, ContentBlock, SamplingMessageContentBlock
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 MetaObject $meta = new MetaObject(),
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: /**
64: * @param array<string, mixed> $data
65: */
66: #[\Override]
67: public static function fromArray(array $data): static
68: {
69: Assert::that($data)->hasOffset('type', 'audio content missing the required "type" key.');
70: $type = $data['type'];
71: Assert::that($type)->isIdentical(self::TYPE, 'audio content "type" must be {other}, {value} given.');
72:
73: Assert::that($data)->hasOffset('data', 'audio content missing the required "data" key.');
74: $payload = $data['data'];
75: Assert::that($payload)->isString('audio content "data" must be a string, {type} given.');
76:
77: Assert::that($data)->hasOffset('mimeType', 'audio content missing the required "mimeType" key.');
78: $mimeType = $data['mimeType'];
79: Assert::that($mimeType)->isString('audio content "mimeType" must be a string, {type} given.');
80:
81: $annotations = new Annotations();
82:
83: if (\array_key_exists('annotations', $data)) {
84: Assert::that($data['annotations'])
85: ->isArray('audio content "annotations" must be an object, {type} given.')
86: ->isMap('audio content "annotations" must be a string-keyed object.')
87: ;
88: $annotations = Annotations::fromArray($data['annotations']);
89: }
90:
91: $meta = new MetaObject();
92:
93: if (\array_key_exists('_meta', $data)) {
94: Assert::that($data['_meta'])
95: ->isArray('audio content "_meta" must be an object, {type} given.')
96: ->isMap('audio content "_meta" must be a string-keyed object.')
97: ;
98: $meta = MetaObject::fromArray($data['_meta']);
99: }
100:
101: return new self($payload, $mimeType, $annotations, $meta);
102: }
103:
104: #[\Override]
105: public function toArray(): array
106: {
107: $data = [
108: 'data' => $this->data,
109: 'mimeType' => $this->mimeType,
110: 'type' => self::TYPE,
111: ];
112:
113: $annotations = $this->annotations->toArray();
114:
115: if ([] !== $annotations) {
116: $data['annotations'] = $annotations;
117: }
118:
119: $meta = $this->meta->toArray();
120:
121: if ([] !== $meta) {
122: $data['_meta'] = $meta;
123: }
124:
125: return $data;
126: }
127:
128: #[\Override]
129: public function jsonSerialize(): array
130: {
131: return $this->toArray();
132: }
133: }
134: