agent_client_protocol_schema/v1/plan.rs
1//! Execution plans for complex tasks that require multiple steps.
2//!
3//! Plans are strategies that agents share with clients through session updates,
4//! providing real-time visibility into their thinking and progress.
5//!
6//! See: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
7
8#[cfg(feature = "unstable_plan_operations")]
9use std::sync::Arc;
10
11#[cfg(feature = "unstable_plan_operations")]
12use derive_more::{Display, From};
13use schemars::JsonSchema;
14use serde::{Deserialize, Serialize};
15use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
16
17use crate::{IntoOption, Meta, SkipListener};
18
19/// An execution plan for accomplishing complex tasks.
20///
21/// Plans consist of multiple entries representing individual tasks or goals.
22/// Agents report plans to clients to provide visibility into their execution strategy.
23/// Plans can evolve during execution as the agent discovers new requirements or completes tasks.
24///
25/// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
26#[serde_as]
27#[skip_serializing_none]
28#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
29#[serde(rename_all = "camelCase")]
30#[non_exhaustive]
31pub struct Plan {
32 /// The list of tasks to be accomplished.
33 ///
34 /// When updating a plan, the agent must send a complete list of all entries
35 /// with their current status. The client replaces the entire plan with each update.
36 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
37 pub entries: Vec<PlanEntry>,
38 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
39 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
40 /// these keys.
41 ///
42 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
43 #[serde(rename = "_meta")]
44 pub meta: Option<Meta>,
45}
46
47impl Plan {
48 #[must_use]
49 pub fn new(entries: Vec<PlanEntry>) -> Self {
50 Self {
51 entries,
52 meta: None,
53 }
54 }
55
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 #[must_use]
62 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
63 self.meta = meta.into_option();
64 self
65 }
66}
67
68/// **UNSTABLE**
69///
70/// This capability is not part of the spec yet, and may be removed or changed at any point.
71///
72/// Unique identifier for a plan within a session.
73#[cfg(feature = "unstable_plan_operations")]
74#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
75#[serde(transparent)]
76#[from(Arc<str>, String, &'static str)]
77#[non_exhaustive]
78pub struct PlanId(pub Arc<str>);
79
80#[cfg(feature = "unstable_plan_operations")]
81impl PlanId {
82 #[must_use]
83 pub fn new(id: impl Into<Arc<str>>) -> Self {
84 Self(id.into())
85 }
86}
87
88/// **UNSTABLE**
89///
90/// This capability is not part of the spec yet, and may be removed or changed at any point.
91///
92/// A content update for a plan identified by ID.
93#[cfg(feature = "unstable_plan_operations")]
94#[skip_serializing_none]
95#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
96#[serde(rename_all = "camelCase")]
97#[non_exhaustive]
98pub struct PlanUpdate {
99 /// The updated plan content.
100 pub plan: PlanUpdateContent,
101 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
102 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
103 /// these keys.
104 ///
105 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
106 #[serde(rename = "_meta")]
107 pub meta: Option<Meta>,
108}
109
110#[cfg(feature = "unstable_plan_operations")]
111impl PlanUpdate {
112 #[must_use]
113 pub fn new(plan: PlanUpdateContent) -> Self {
114 Self { plan, meta: None }
115 }
116
117 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
118 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
119 /// these keys.
120 ///
121 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
122 #[must_use]
123 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
124 self.meta = meta.into_option();
125 self
126 }
127}
128
129/// **UNSTABLE**
130///
131/// This capability is not part of the spec yet, and may be removed or changed at any point.
132///
133/// Updated content for a plan.
134#[cfg(feature = "unstable_plan_operations")]
135#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
136#[serde(tag = "type", rename_all = "snake_case")]
137#[schemars(extend("discriminator" = {"propertyName": "type"}))]
138#[non_exhaustive]
139pub enum PlanUpdateContent {
140 /// Structured plan entries.
141 Items(PlanItems),
142 /// A URI pointing to a file containing the plan.
143 File(PlanFile),
144 /// Raw markdown content for the plan.
145 Markdown(PlanMarkdown),
146}
147
148#[cfg(feature = "unstable_plan_operations")]
149impl PlanUpdateContent {
150 #[must_use]
151 pub fn items(id: impl Into<PlanId>, entries: Vec<PlanEntry>) -> Self {
152 Self::Items(PlanItems::new(id, entries))
153 }
154
155 #[must_use]
156 pub fn file(id: impl Into<PlanId>, uri: impl Into<String>) -> Self {
157 Self::File(PlanFile::new(id, uri))
158 }
159
160 #[must_use]
161 pub fn markdown(id: impl Into<PlanId>, content: impl Into<String>) -> Self {
162 Self::Markdown(PlanMarkdown::new(id, content))
163 }
164}
165
166/// **UNSTABLE**
167///
168/// This capability is not part of the spec yet, and may be removed or changed at any point.
169///
170/// A plan represented as structured entries.
171#[cfg(feature = "unstable_plan_operations")]
172#[serde_as]
173#[skip_serializing_none]
174#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
175#[serde(rename_all = "camelCase")]
176#[non_exhaustive]
177pub struct PlanItems {
178 /// The plan ID to update.
179 pub id: PlanId,
180 /// The list of tasks to be accomplished.
181 ///
182 /// When updating an item-based plan, the agent must send a complete list of all entries
183 /// with their current status. The client replaces that plan with each update.
184 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
185 pub entries: Vec<PlanEntry>,
186 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
187 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
188 /// these keys.
189 ///
190 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
191 #[serde(rename = "_meta")]
192 pub meta: Option<Meta>,
193}
194
195#[cfg(feature = "unstable_plan_operations")]
196impl PlanItems {
197 #[must_use]
198 pub fn new(id: impl Into<PlanId>, entries: Vec<PlanEntry>) -> Self {
199 Self {
200 id: id.into(),
201 entries,
202 meta: None,
203 }
204 }
205
206 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
207 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
208 /// these keys.
209 ///
210 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
211 #[must_use]
212 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
213 self.meta = meta.into_option();
214 self
215 }
216}
217
218/// **UNSTABLE**
219///
220/// This capability is not part of the spec yet, and may be removed or changed at any point.
221///
222/// A plan represented by a file URI.
223#[cfg(feature = "unstable_plan_operations")]
224#[skip_serializing_none]
225#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
226#[serde(rename_all = "camelCase")]
227#[non_exhaustive]
228pub struct PlanFile {
229 /// The plan ID to update.
230 pub id: PlanId,
231 /// The URI of the file containing the plan.
232 pub uri: String,
233 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
234 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
235 /// these keys.
236 ///
237 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
238 #[serde(rename = "_meta")]
239 pub meta: Option<Meta>,
240}
241
242#[cfg(feature = "unstable_plan_operations")]
243impl PlanFile {
244 #[must_use]
245 pub fn new(id: impl Into<PlanId>, uri: impl Into<String>) -> Self {
246 Self {
247 id: id.into(),
248 uri: uri.into(),
249 meta: None,
250 }
251 }
252
253 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
254 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
255 /// these keys.
256 ///
257 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
258 #[must_use]
259 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
260 self.meta = meta.into_option();
261 self
262 }
263}
264
265/// **UNSTABLE**
266///
267/// This capability is not part of the spec yet, and may be removed or changed at any point.
268///
269/// A plan represented as raw markdown content.
270#[cfg(feature = "unstable_plan_operations")]
271#[skip_serializing_none]
272#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
273#[serde(rename_all = "camelCase")]
274#[non_exhaustive]
275pub struct PlanMarkdown {
276 /// The plan ID to update.
277 pub id: PlanId,
278 /// Markdown content for the plan.
279 pub content: String,
280 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
281 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
282 /// these keys.
283 ///
284 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
285 #[serde(rename = "_meta")]
286 pub meta: Option<Meta>,
287}
288
289#[cfg(feature = "unstable_plan_operations")]
290impl PlanMarkdown {
291 #[must_use]
292 pub fn new(id: impl Into<PlanId>, content: impl Into<String>) -> Self {
293 Self {
294 id: id.into(),
295 content: content.into(),
296 meta: None,
297 }
298 }
299
300 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
301 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
302 /// these keys.
303 ///
304 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
305 #[must_use]
306 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
307 self.meta = meta.into_option();
308 self
309 }
310}
311
312/// **UNSTABLE**
313///
314/// This capability is not part of the spec yet, and may be removed or changed at any point.
315///
316/// Removal notice for a plan identified by ID.
317#[cfg(feature = "unstable_plan_operations")]
318#[skip_serializing_none]
319#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
320#[serde(rename_all = "camelCase")]
321#[non_exhaustive]
322pub struct PlanRemoved {
323 /// The plan ID to remove.
324 pub id: PlanId,
325 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
326 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
327 /// these keys.
328 ///
329 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
330 #[serde(rename = "_meta")]
331 pub meta: Option<Meta>,
332}
333
334#[cfg(feature = "unstable_plan_operations")]
335impl PlanRemoved {
336 #[must_use]
337 pub fn new(id: impl Into<PlanId>) -> Self {
338 Self {
339 id: id.into(),
340 meta: None,
341 }
342 }
343
344 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
345 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
346 /// these keys.
347 ///
348 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
349 #[must_use]
350 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
351 self.meta = meta.into_option();
352 self
353 }
354}
355
356/// **UNSTABLE**
357///
358/// This capability is not part of the spec yet, and may be removed or changed at any point.
359///
360/// Capabilities for receiving `plan_update` and `plan_removed` session updates.
361#[cfg(feature = "unstable_plan_operations")]
362#[skip_serializing_none]
363#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
364#[serde(rename_all = "camelCase")]
365#[non_exhaustive]
366pub struct PlanCapabilities {
367 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
368 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
369 /// these keys.
370 ///
371 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
372 #[serde(rename = "_meta")]
373 pub meta: Option<Meta>,
374}
375
376#[cfg(feature = "unstable_plan_operations")]
377impl PlanCapabilities {
378 #[must_use]
379 pub fn new() -> Self {
380 Self::default()
381 }
382
383 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
384 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
385 /// these keys.
386 ///
387 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
388 #[must_use]
389 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
390 self.meta = meta.into_option();
391 self
392 }
393}
394
395/// A single entry in the execution plan.
396///
397/// Represents a task or goal that the assistant intends to accomplish
398/// as part of fulfilling the user's request.
399/// See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)
400#[skip_serializing_none]
401#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
402#[serde(rename_all = "camelCase")]
403#[non_exhaustive]
404pub struct PlanEntry {
405 /// Human-readable description of what this task aims to accomplish.
406 pub content: String,
407 /// The relative importance of this task.
408 /// Used to indicate which tasks are most critical to the overall goal.
409 pub priority: PlanEntryPriority,
410 /// Current execution status of this task.
411 pub status: PlanEntryStatus,
412 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
413 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
414 /// these keys.
415 ///
416 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
417 #[serde(rename = "_meta")]
418 pub meta: Option<Meta>,
419}
420
421impl PlanEntry {
422 #[must_use]
423 pub fn new(
424 content: impl Into<String>,
425 priority: PlanEntryPriority,
426 status: PlanEntryStatus,
427 ) -> Self {
428 Self {
429 content: content.into(),
430 priority,
431 status,
432 meta: None,
433 }
434 }
435
436 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
437 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
438 /// these keys.
439 ///
440 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
441 #[must_use]
442 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
443 self.meta = meta.into_option();
444 self
445 }
446}
447
448/// Priority levels for plan entries.
449///
450/// Used to indicate the relative importance or urgency of different
451/// tasks in the execution plan.
452/// See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)
453#[derive(Deserialize, Serialize, JsonSchema, Debug, Clone, PartialEq, Eq)]
454#[serde(rename_all = "snake_case")]
455#[non_exhaustive]
456pub enum PlanEntryPriority {
457 /// High priority task - critical to the overall goal.
458 High,
459 /// Medium priority task - important but not critical.
460 Medium,
461 /// Low priority task - nice to have but not essential.
462 Low,
463}
464
465/// Status of a plan entry in the execution flow.
466///
467/// Tracks the lifecycle of each task from planning through completion.
468/// See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)
469#[derive(Deserialize, Serialize, JsonSchema, Debug, Clone, PartialEq, Eq)]
470#[serde(rename_all = "snake_case")]
471#[non_exhaustive]
472pub enum PlanEntryStatus {
473 /// The task has not started yet.
474 Pending,
475 /// The task is currently being worked on.
476 InProgress,
477 /// The task has been successfully completed.
478 Completed,
479}