agent_client_protocol_schema/v1/tool_call.rs
1//! Tool calls represent actions that language models request agents to perform.
2//!
3//! When an LLM determines it needs to interact with external systems—like reading files,
4//! running code, or fetching data—it generates tool calls that the agent executes on its behalf.
5//!
6/// See protocol docs: [Tool Calls](https://agentclientprotocol.com/protocol/tool-calls)
7use std::{path::PathBuf, sync::Arc};
8
9use derive_more::{Display, From};
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
13
14use crate::{ContentBlock, Error, IntoOption, Meta, SkipListener, TerminalId};
15
16/// Represents a tool call that the language model has requested.
17///
18/// Tool calls are actions that the agent executes on behalf of the language model,
19/// such as reading files, executing code, or fetching data from external sources.
20///
21/// See protocol docs: [Tool Calls](https://agentclientprotocol.com/protocol/tool-calls)
22#[serde_as]
23#[skip_serializing_none]
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
25#[serde(rename_all = "camelCase")]
26#[non_exhaustive]
27pub struct ToolCall {
28 /// Unique identifier for this tool call within the session.
29 pub tool_call_id: ToolCallId,
30 /// Human-readable title describing what the tool is doing.
31 pub title: String,
32 /// The category of tool being invoked.
33 /// Helps clients choose appropriate icons and UI treatment.
34 #[serde(default, skip_serializing_if = "ToolKind::is_default")]
35 pub kind: ToolKind,
36 /// Current execution status of the tool call.
37 #[serde(default, skip_serializing_if = "ToolCallStatus::is_default")]
38 pub status: ToolCallStatus,
39 /// Content produced by the tool call.
40 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
41 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
42 #[serde(default, skip_serializing_if = "Vec::is_empty")]
43 pub content: Vec<ToolCallContent>,
44 /// File locations affected by this tool call.
45 /// Enables "follow-along" features in clients.
46 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
47 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
48 #[serde(default, skip_serializing_if = "Vec::is_empty")]
49 pub locations: Vec<ToolCallLocation>,
50 /// Raw input parameters sent to the tool.
51 pub raw_input: Option<serde_json::Value>,
52 /// Raw output returned by the tool.
53 pub raw_output: Option<serde_json::Value>,
54 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
55 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
56 /// these keys.
57 ///
58 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
59 #[serde(rename = "_meta")]
60 pub meta: Option<Meta>,
61}
62
63impl ToolCall {
64 /// Builds [`ToolCall`] with the required fields set; optional fields start unset or empty.
65 #[must_use]
66 pub fn new(tool_call_id: impl Into<ToolCallId>, title: impl Into<String>) -> Self {
67 Self {
68 tool_call_id: tool_call_id.into(),
69 title: title.into(),
70 kind: ToolKind::default(),
71 status: ToolCallStatus::default(),
72 content: Vec::default(),
73 locations: Vec::default(),
74 raw_input: None,
75 raw_output: None,
76 meta: None,
77 }
78 }
79
80 /// The category of tool being invoked.
81 /// Helps clients choose appropriate icons and UI treatment.
82 #[must_use]
83 pub fn kind(mut self, kind: ToolKind) -> Self {
84 self.kind = kind;
85 self
86 }
87
88 /// Current execution status of the tool call.
89 #[must_use]
90 pub fn status(mut self, status: ToolCallStatus) -> Self {
91 self.status = status;
92 self
93 }
94
95 /// Content produced by the tool call.
96 #[must_use]
97 pub fn content(mut self, content: Vec<ToolCallContent>) -> Self {
98 self.content = content;
99 self
100 }
101
102 /// File locations affected by this tool call.
103 /// Enables "follow-along" features in clients.
104 #[must_use]
105 pub fn locations(mut self, locations: Vec<ToolCallLocation>) -> Self {
106 self.locations = locations;
107 self
108 }
109
110 /// Raw input parameters sent to the tool.
111 #[must_use]
112 pub fn raw_input(mut self, raw_input: impl IntoOption<serde_json::Value>) -> Self {
113 self.raw_input = raw_input.into_option();
114 self
115 }
116
117 /// Raw output returned by the tool.
118 #[must_use]
119 pub fn raw_output(mut self, raw_output: impl IntoOption<serde_json::Value>) -> Self {
120 self.raw_output = raw_output.into_option();
121 self
122 }
123
124 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
125 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
126 /// these keys.
127 ///
128 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
129 #[must_use]
130 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
131 self.meta = meta.into_option();
132 self
133 }
134
135 /// Update an existing tool call with the values in the provided update
136 /// fields. Fields with collections of values are overwritten, not extended.
137 pub fn update(&mut self, fields: ToolCallUpdateFields) {
138 if let Some(title) = fields.title {
139 self.title = title;
140 }
141 if let Some(kind) = fields.kind {
142 self.kind = kind;
143 }
144 if let Some(status) = fields.status {
145 self.status = status;
146 }
147 if let Some(content) = fields.content {
148 self.content = content;
149 }
150 if let Some(locations) = fields.locations {
151 self.locations = locations;
152 }
153 if let Some(raw_input) = fields.raw_input {
154 self.raw_input = Some(raw_input);
155 }
156 if let Some(raw_output) = fields.raw_output {
157 self.raw_output = Some(raw_output);
158 }
159 }
160}
161
162/// An update to an existing tool call.
163///
164/// Used to report progress and results as tools execute. All fields except
165/// the tool call ID are optional - only changed fields need to be included.
166///
167/// See protocol docs: [Updating](https://agentclientprotocol.com/protocol/tool-calls#updating)
168#[skip_serializing_none]
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
170#[serde(rename_all = "camelCase")]
171#[non_exhaustive]
172pub struct ToolCallUpdate {
173 /// The ID of the tool call being updated.
174 pub tool_call_id: ToolCallId,
175 /// Fields being updated.
176 #[serde(flatten)]
177 pub fields: ToolCallUpdateFields,
178 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
179 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
180 /// these keys.
181 ///
182 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
183 #[serde(rename = "_meta")]
184 pub meta: Option<Meta>,
185}
186
187impl ToolCallUpdate {
188 /// Builds [`ToolCallUpdate`] with the required fields set; optional fields start unset or empty.
189 #[must_use]
190 pub fn new(tool_call_id: impl Into<ToolCallId>, fields: ToolCallUpdateFields) -> Self {
191 Self {
192 tool_call_id: tool_call_id.into(),
193 fields,
194 meta: None,
195 }
196 }
197
198 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
199 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
200 /// these keys.
201 ///
202 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
203 #[must_use]
204 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
205 self.meta = meta.into_option();
206 self
207 }
208}
209
210/// Optional fields that can be updated in a tool call.
211///
212/// All fields are optional - only include the ones being changed.
213/// Collections (content, locations) are overwritten, not extended.
214///
215/// See protocol docs: [Updating](https://agentclientprotocol.com/protocol/tool-calls#updating)
216#[serde_as]
217#[skip_serializing_none]
218#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
219#[serde(rename_all = "camelCase")]
220#[non_exhaustive]
221pub struct ToolCallUpdateFields {
222 /// Update the tool kind.
223 #[serde_as(deserialize_as = "DefaultOnError")]
224 #[schemars(extend("x-deserialize-default-on-error" = true))]
225 #[serde(default)]
226 pub kind: Option<ToolKind>,
227 /// Update the execution status.
228 #[serde_as(deserialize_as = "DefaultOnError")]
229 #[schemars(extend("x-deserialize-default-on-error" = true))]
230 #[serde(default)]
231 pub status: Option<ToolCallStatus>,
232 /// Update the human-readable title.
233 pub title: Option<String>,
234 /// Replace the content collection.
235 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
236 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
237 #[serde(default)]
238 pub content: Option<Vec<ToolCallContent>>,
239 /// Replace the locations collection.
240 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
241 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
242 #[serde(default)]
243 pub locations: Option<Vec<ToolCallLocation>>,
244 /// Update the raw input.
245 pub raw_input: Option<serde_json::Value>,
246 /// Update the raw output.
247 pub raw_output: Option<serde_json::Value>,
248}
249
250impl ToolCallUpdateFields {
251 /// Builds [`ToolCallUpdateFields`] with the required fields set; optional fields start unset or empty.
252 #[must_use]
253 pub fn new() -> Self {
254 Self::default()
255 }
256
257 /// Update the tool kind.
258 #[must_use]
259 pub fn kind(mut self, kind: impl IntoOption<ToolKind>) -> Self {
260 self.kind = kind.into_option();
261 self
262 }
263
264 /// Update the execution status.
265 #[must_use]
266 pub fn status(mut self, status: impl IntoOption<ToolCallStatus>) -> Self {
267 self.status = status.into_option();
268 self
269 }
270
271 /// Update the human-readable title.
272 #[must_use]
273 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
274 self.title = title.into_option();
275 self
276 }
277
278 /// Replace the content collection.
279 #[must_use]
280 pub fn content(mut self, content: impl IntoOption<Vec<ToolCallContent>>) -> Self {
281 self.content = content.into_option();
282 self
283 }
284
285 /// Replace the locations collection.
286 #[must_use]
287 pub fn locations(mut self, locations: impl IntoOption<Vec<ToolCallLocation>>) -> Self {
288 self.locations = locations.into_option();
289 self
290 }
291
292 /// Update the raw input.
293 #[must_use]
294 pub fn raw_input(mut self, raw_input: impl IntoOption<serde_json::Value>) -> Self {
295 self.raw_input = raw_input.into_option();
296 self
297 }
298
299 /// Update the raw output.
300 #[must_use]
301 pub fn raw_output(mut self, raw_output: impl IntoOption<serde_json::Value>) -> Self {
302 self.raw_output = raw_output.into_option();
303 self
304 }
305}
306
307/// If a given tool call doesn't exist yet, allows for attempting to construct
308/// one from a tool call update if possible.
309impl TryFrom<ToolCallUpdate> for ToolCall {
310 type Error = Error;
311
312 fn try_from(update: ToolCallUpdate) -> Result<Self, Self::Error> {
313 let ToolCallUpdate {
314 tool_call_id,
315 fields:
316 ToolCallUpdateFields {
317 kind,
318 status,
319 title,
320 content,
321 locations,
322 raw_input,
323 raw_output,
324 },
325 meta,
326 } = update;
327
328 Ok(Self {
329 tool_call_id,
330 title: title.ok_or_else(|| {
331 Error::invalid_params().data(serde_json::json!("title is required for a tool call"))
332 })?,
333 kind: kind.unwrap_or_default(),
334 status: status.unwrap_or_default(),
335 content: content.unwrap_or_default(),
336 locations: locations.unwrap_or_default(),
337 raw_input,
338 raw_output,
339 meta,
340 })
341 }
342}
343
344impl From<ToolCall> for ToolCallUpdate {
345 fn from(value: ToolCall) -> Self {
346 let ToolCall {
347 tool_call_id,
348 title,
349 kind,
350 status,
351 content,
352 locations,
353 raw_input,
354 raw_output,
355 meta,
356 } = value;
357 Self {
358 tool_call_id,
359 fields: ToolCallUpdateFields {
360 kind: Some(kind),
361 status: Some(status),
362 title: Some(title),
363 content: Some(content),
364 locations: Some(locations),
365 raw_input,
366 raw_output,
367 },
368 meta,
369 }
370 }
371}
372
373/// Unique identifier for a tool call within a session.
374#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
375#[serde(transparent)]
376#[from(Arc<str>, String, &'static str)]
377#[non_exhaustive]
378pub struct ToolCallId(pub Arc<str>);
379
380impl ToolCallId {
381 /// Wraps a protocol string as a typed [`ToolCallId`].
382 #[must_use]
383 pub fn new(id: impl Into<Arc<str>>) -> Self {
384 Self(id.into())
385 }
386}
387
388impl IntoOption<ToolCallId> for &str {
389 fn into_option(self) -> Option<ToolCallId> {
390 Some(ToolCallId::new(self))
391 }
392}
393
394/// Categories of tools that can be invoked.
395///
396/// Tool kinds help clients choose appropriate icons and optimize how they
397/// display tool execution progress.
398///
399/// See protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-calls#creating)
400#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
401#[serde(rename_all = "snake_case")]
402#[non_exhaustive]
403pub enum ToolKind {
404 /// Reading files or data.
405 Read,
406 /// Modifying files or content.
407 Edit,
408 /// Removing files or data.
409 Delete,
410 /// Moving or renaming files.
411 Move,
412 /// Searching for information.
413 Search,
414 /// Running commands or code.
415 Execute,
416 /// Internal reasoning or planning.
417 Think,
418 /// Retrieving external data.
419 Fetch,
420 /// Switching the current session mode.
421 SwitchMode,
422 /// Other tool types (default).
423 #[default]
424 #[serde(other)]
425 Other,
426}
427
428impl ToolKind {
429 #[expect(clippy::trivially_copy_pass_by_ref, reason = "Required by serde")]
430 fn is_default(&self) -> bool {
431 matches!(self, ToolKind::Other)
432 }
433}
434
435/// Execution status of a tool call.
436///
437/// Tool calls progress through different statuses during their lifecycle.
438///
439/// See protocol docs: [Status](https://agentclientprotocol.com/protocol/tool-calls#status)
440#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
441#[serde(rename_all = "snake_case")]
442#[non_exhaustive]
443pub enum ToolCallStatus {
444 /// The tool call hasn't started running yet because the input is either
445 /// streaming or we're awaiting approval.
446 #[default]
447 Pending,
448 /// The tool call is currently running.
449 InProgress,
450 /// The tool call completed successfully.
451 Completed,
452 /// The tool call failed with an error.
453 Failed,
454}
455
456impl ToolCallStatus {
457 #[expect(clippy::trivially_copy_pass_by_ref, reason = "Required by serde")]
458 fn is_default(&self) -> bool {
459 matches!(self, ToolCallStatus::Pending)
460 }
461}
462
463/// Content produced by a tool call.
464///
465/// Tool calls can produce different types of content including
466/// standard content blocks (text, images) or file diffs.
467///
468/// See protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)
469#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
470#[serde(tag = "type", rename_all = "snake_case")]
471#[schemars(extend("discriminator" = {"propertyName": "type"}))]
472#[non_exhaustive]
473#[expect(clippy::large_enum_variant)]
474pub enum ToolCallContent {
475 /// Standard content block (text, images, resources).
476 Content(Content),
477 /// File modification shown as a diff.
478 Diff(Diff),
479 /// Embed a terminal created with `terminal/create` by its id.
480 ///
481 /// The terminal must be added before calling `terminal/release`.
482 ///
483 /// See protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminals)
484 Terminal(Terminal),
485}
486
487impl<T: Into<ContentBlock>> From<T> for ToolCallContent {
488 fn from(content: T) -> Self {
489 ToolCallContent::Content(Content::new(content))
490 }
491}
492
493impl From<Diff> for ToolCallContent {
494 fn from(diff: Diff) -> Self {
495 ToolCallContent::Diff(diff)
496 }
497}
498
499/// Standard content block (text, images, resources).
500#[skip_serializing_none]
501#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
502#[serde(rename_all = "camelCase")]
503#[non_exhaustive]
504pub struct Content {
505 /// The actual content block.
506 pub content: ContentBlock,
507 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
508 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
509 /// these keys.
510 ///
511 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
512 #[serde(rename = "_meta")]
513 pub meta: Option<Meta>,
514}
515
516impl Content {
517 /// Builds [`Content`] with the required fields set; optional fields start unset or empty.
518 #[must_use]
519 pub fn new(content: impl Into<ContentBlock>) -> Self {
520 Self {
521 content: content.into(),
522 meta: None,
523 }
524 }
525
526 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
527 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
528 /// these keys.
529 ///
530 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
531 #[must_use]
532 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
533 self.meta = meta.into_option();
534 self
535 }
536}
537
538/// Embed a terminal created with `terminal/create` by its id.
539///
540/// The terminal must be added before calling `terminal/release`.
541///
542/// See protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminals)
543#[skip_serializing_none]
544#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
545#[serde(rename_all = "camelCase")]
546#[non_exhaustive]
547pub struct Terminal {
548 /// Identifier of the terminal instance to embed in the content stream.
549 pub terminal_id: TerminalId,
550 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
551 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
552 /// these keys.
553 ///
554 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
555 #[serde(rename = "_meta")]
556 pub meta: Option<Meta>,
557}
558
559impl Terminal {
560 /// Builds [`Terminal`] with the required fields set; optional fields start unset or empty.
561 #[must_use]
562 pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
563 Self {
564 terminal_id: terminal_id.into(),
565 meta: None,
566 }
567 }
568
569 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
570 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
571 /// these keys.
572 ///
573 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
574 #[must_use]
575 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
576 self.meta = meta.into_option();
577 self
578 }
579}
580
581/// A diff representing file modifications.
582///
583/// Shows changes to files in a format suitable for display in the client UI.
584///
585/// See protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)
586#[skip_serializing_none]
587#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
588#[serde(rename_all = "camelCase")]
589#[non_exhaustive]
590pub struct Diff {
591 /// The file path being modified.
592 pub path: PathBuf,
593 /// The original content (None for new files).
594 pub old_text: Option<String>,
595 /// The new content after modification.
596 pub new_text: String,
597 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
598 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
599 /// these keys.
600 ///
601 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
602 #[serde(rename = "_meta")]
603 pub meta: Option<Meta>,
604}
605
606impl Diff {
607 /// Builds [`Diff`] with the required fields set; optional fields start unset or empty.
608 #[must_use]
609 pub fn new(path: impl Into<PathBuf>, new_text: impl Into<String>) -> Self {
610 Self {
611 path: path.into(),
612 old_text: None,
613 new_text: new_text.into(),
614 meta: None,
615 }
616 }
617
618 /// The original content (None for new files).
619 #[must_use]
620 pub fn old_text(mut self, old_text: impl IntoOption<String>) -> Self {
621 self.old_text = old_text.into_option();
622 self
623 }
624
625 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
626 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
627 /// these keys.
628 ///
629 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
630 #[must_use]
631 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
632 self.meta = meta.into_option();
633 self
634 }
635}
636
637/// A file location being accessed or modified by a tool.
638///
639/// Enables clients to implement "follow-along" features that track
640/// which files the agent is working with in real-time.
641///
642/// See protocol docs: [Following the Agent](https://agentclientprotocol.com/protocol/tool-calls#following-the-agent)
643#[skip_serializing_none]
644#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
645#[serde(rename_all = "camelCase")]
646#[non_exhaustive]
647pub struct ToolCallLocation {
648 /// The file path being accessed or modified.
649 pub path: PathBuf,
650 /// Optional line number within the file.
651 #[serde(default)]
652 pub line: Option<u32>,
653 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
654 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
655 /// these keys.
656 ///
657 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
658 #[serde(rename = "_meta")]
659 pub meta: Option<Meta>,
660}
661
662impl ToolCallLocation {
663 /// Builds [`ToolCallLocation`] with the required fields set; optional fields start unset or empty.
664 #[must_use]
665 pub fn new(path: impl Into<PathBuf>) -> Self {
666 Self {
667 path: path.into(),
668 line: None,
669 meta: None,
670 }
671 }
672
673 /// Optional line number within the file.
674 #[must_use]
675 pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
676 self.line = line.into_option();
677 self
678 }
679
680 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
681 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
682 /// these keys.
683 ///
684 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
685 #[must_use]
686 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
687 self.meta = meta.into_option();
688 self
689 }
690}