Skip to main content

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}