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