Skip to main content

a2a_protocol_client/methods/
tasks.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Tom F.
3
4//! Task management client methods.
5//!
6//! Provides `get_task`, `list_tasks`, `cancel_task`, and `subscribe_to_task`
7//! on [`A2aClient`].
8
9use a2a_protocol_types::{
10    CancelTaskParams, ListTasksParams, Task, TaskIdParams, TaskListResponse, TaskQueryParams,
11};
12
13use crate::client::A2aClient;
14use crate::error::{ClientError, ClientResult};
15use crate::interceptor::{ClientRequest, ClientResponse};
16use crate::streaming::EventStream;
17
18impl A2aClient {
19    /// Retrieves a task by ID.
20    ///
21    /// Calls the `GetTask` JSON-RPC method.
22    ///
23    /// # Errors
24    ///
25    /// Returns [`ClientError::Protocol`] with [`a2a_protocol_types::ErrorCode::TaskNotFound`]
26    /// if no task with the given ID exists.
27    pub async fn get_task(&self, params: TaskQueryParams) -> ClientResult<Task> {
28        const METHOD: &str = "GetTask";
29
30        let params_value = serde_json::to_value(&params).map_err(ClientError::Serialization)?;
31
32        let mut req = ClientRequest::new(METHOD, params_value);
33        self.interceptors.run_before(&mut req).await?;
34
35        let result = self
36            .transport
37            .send_request(METHOD, req.params, &req.extra_headers)
38            .await?;
39
40        let resp = ClientResponse {
41            method: METHOD.to_owned(),
42            result,
43            status_code: 200,
44        };
45        self.interceptors.run_after(&resp).await?;
46
47        serde_json::from_value::<Task>(resp.result).map_err(ClientError::Serialization)
48    }
49
50    /// Lists tasks visible to the caller.
51    ///
52    /// Calls the `ListTasks` JSON-RPC method. Results are paginated; use
53    /// `params.page_token` to fetch subsequent pages.
54    ///
55    /// # Errors
56    ///
57    /// Returns [`ClientError`] on transport or protocol errors.
58    pub async fn list_tasks(&self, params: ListTasksParams) -> ClientResult<TaskListResponse> {
59        const METHOD: &str = "ListTasks";
60
61        let params_value = serde_json::to_value(&params).map_err(ClientError::Serialization)?;
62
63        let mut req = ClientRequest::new(METHOD, params_value);
64        self.interceptors.run_before(&mut req).await?;
65
66        let result = self
67            .transport
68            .send_request(METHOD, req.params, &req.extra_headers)
69            .await?;
70
71        let resp = ClientResponse {
72            method: METHOD.to_owned(),
73            result,
74            status_code: 200,
75        };
76        self.interceptors.run_after(&resp).await?;
77
78        serde_json::from_value::<TaskListResponse>(resp.result).map_err(ClientError::Serialization)
79    }
80
81    /// Requests cancellation of a running task.
82    ///
83    /// Calls the `CancelTask` JSON-RPC method. Returns the task in its
84    /// post-cancellation state.
85    ///
86    /// # Errors
87    ///
88    /// Returns [`ClientError::Protocol`] with
89    /// [`a2a_protocol_types::ErrorCode::TaskNotCancelable`] if the task cannot be
90    /// canceled in its current state.
91    pub async fn cancel_task(&self, id: impl Into<String>) -> ClientResult<Task> {
92        const METHOD: &str = "CancelTask";
93
94        let params = CancelTaskParams {
95            tenant: None,
96            id: id.into(),
97            metadata: None,
98        };
99        let params_value = serde_json::to_value(&params).map_err(ClientError::Serialization)?;
100
101        let mut req = ClientRequest::new(METHOD, params_value);
102        self.interceptors.run_before(&mut req).await?;
103
104        let result = self
105            .transport
106            .send_request(METHOD, req.params, &req.extra_headers)
107            .await?;
108
109        let resp = ClientResponse {
110            method: METHOD.to_owned(),
111            result,
112            status_code: 200,
113        };
114        self.interceptors.run_after(&resp).await?;
115
116        serde_json::from_value::<Task>(resp.result).map_err(ClientError::Serialization)
117    }
118
119    /// Subscribes to the SSE stream for an in-progress task.
120    ///
121    /// Calls the `SubscribeToTask` method. Useful after an unexpected
122    /// disconnection from a `SendStreamingMessage` call.
123    ///
124    /// Events already delivered before the reconnect are **not** replayed.
125    ///
126    /// # Errors
127    ///
128    /// Returns [`ClientError::Protocol`] with
129    /// [`a2a_protocol_types::ErrorCode::TaskNotFound`] if the task is not in a
130    /// streaming-eligible state.
131    pub async fn subscribe_to_task(&self, id: impl Into<String>) -> ClientResult<EventStream> {
132        const METHOD: &str = "SubscribeToTask";
133
134        let params = TaskIdParams {
135            tenant: None,
136            id: id.into(),
137        };
138        let params_value = serde_json::to_value(&params).map_err(ClientError::Serialization)?;
139
140        let mut req = ClientRequest::new(METHOD, params_value);
141        self.interceptors.run_before(&mut req).await?;
142
143        self.transport
144            .send_streaming_request(METHOD, req.params, &req.extra_headers)
145            .await
146    }
147}