Skip to main content

a2a_server/task_store/
store.rs

1// Copyright AGNTCY Contributors (https://github.com/agntcy)
2// Copyright A2A Contributors (https://github.com/a2aproject)
3// SPDX-License-Identifier: Apache-2.0
4use a2a::*;
5use async_trait::async_trait;
6
7/// Version counter for optimistic concurrency control.
8pub type TaskVersion = u64;
9
10/// A task stored with version metadata.
11#[derive(Debug, Clone)]
12pub struct StoredTask {
13    pub task: Task,
14    pub version: TaskVersion,
15}
16
17/// Interface for persisting and retrieving tasks.
18#[async_trait]
19pub trait TaskStore: Send + Sync + 'static {
20    /// Create a new task. Returns the initial version.
21    async fn create(&self, task: Task) -> Result<TaskVersion, A2AError>;
22
23    /// Update an existing task. Returns the new version.
24    async fn update(&self, task: Task) -> Result<TaskVersion, A2AError>;
25
26    /// Get a task by ID.
27    async fn get(&self, task_id: &str) -> Result<Option<Task>, A2AError>;
28
29    /// List tasks matching the request criteria.
30    ///
31    /// An implementation must honour `req.page_size` and set
32    /// `next_page_token` when more tasks remain. `DefaultRequestHandler`
33    /// clamps `page_size` to
34    /// [`MAX_PAGE_SIZE`](crate::pagination::MAX_PAGE_SIZE) before calling
35    /// this, and truncates the response to that bound if more comes back --
36    /// so a store that ignores `page_size` will have its extra tasks
37    /// dropped, and the caller loses them, because the handler cannot
38    /// synthesise a continuation token for a paging scheme it does not own.
39    async fn list(&self, req: &ListTasksRequest) -> Result<ListTasksResponse, A2AError>;
40
41    /// Atomically check that a task is not in a terminal state and transition
42    /// it to `CANCELED`, returning the updated task.
43    ///
44    /// `TASK_NOT_CANCELABLE` if the task is already terminal,
45    /// `TASK_NOT_FOUND` if it does not exist.
46    ///
47    /// Deliberately has no default implementation. A default could only read
48    /// and then write, which is the check-then-act race this method exists to
49    /// close, and an implementor who did not notice would inherit it silently.
50    /// Serialise the check and the transition -- see `InMemoryTaskStore`, which
51    /// holds its write lock across both.
52    async fn begin_cancel(&self, task_id: &str) -> Result<Task, A2AError>;
53}