Skip to main content

lean_ctx/core/a2a/
task.rs

1pub mod delivery_authority;
2pub mod delivery_delegation;
3pub mod policy_file;
4
5const MAX_TASK_STORE_BYTES: u64 = 8 * 1024 * 1024;
6const MAX_TASKS: usize = 10_000;
7pub const MAX_TASK_DESCRIPTOR_BYTES: usize = 256 * 1024;
8const MAX_DESCRIPTOR_STRING_BYTES: usize = 256;
9const MAX_DESCRIPTION_BYTES: usize = 64 * 1024;
10const MAX_ARTIFACT_REFS: usize = 64;
11const MAX_IDEMPOTENCY_RECORDS: usize = 10_000;
12const MAX_IDEMPOTENCY_KEY_BYTES: usize = 128;
13const MAX_TASK_LIFETIME_SECONDS: i64 = 24 * 60 * 60;
14const MAX_POLICY_LIFETIME_SECONDS: i64 = 366 * 24 * 60 * 60;
15const MAX_TRUST_ENTRIES: usize = 1_024;
16/// Accepted clock difference between the signing peer and this receiver.
17const MAX_AUTHORITY_CLOCK_SKEW_SECONDS: i64 = 60;
18/// An idempotency record is only useful while a descriptor bearing that key can
19/// still verify, so retention is bounded by the maximum descriptor lifetime
20/// plus the accepted clock skew. Expired records are pruned instead of growing
21/// until the hard cap turns every later delivery into a store error.
22const IDEMPOTENCY_RETENTION_SECONDS: i64 =
23    MAX_TASK_LIFETIME_SECONDS + MAX_AUTHORITY_CLOCK_SKEW_SECONDS;
24/// Domain tag prefixed to the descriptor signing transcript so a descriptor
25/// signature can never be replayed as a signature over another artifact that
26/// happens to canonicalize to the same bytes.
27const TASK_DESCRIPTOR_SIGNING_DOMAIN: &[u8] = b"leanctx.a2a.task.descriptor.sig.v1\0";
28/// Domain tag for the control transcript. Distinct from the descriptor domain
29/// so a send signature can never be replayed as a `tasks/get` or `tasks/cancel`
30/// signature, nor the reverse, whatever the canonical bodies look like.
31const TASK_CONTROL_SIGNING_DOMAIN: &[u8] = b"leanctx.a2a.task.control.sig.v1\0";
32/// A control operation carries no payload and is answered immediately, so its
33/// validity window is bounded far tighter than a task's — strictly stricter
34/// than `MAX_TASK_LIFETIME_SECONDS`, never looser.
35const MAX_TASK_CONTROL_LIFETIME_SECONDS: i64 = 15 * 60;
36const MAX_CANCEL_REASON_BYTES: usize = 512;
37const MAX_CONTROL_NONCE_BYTES: usize = MAX_IDEMPOTENCY_KEY_BYTES;
38const DIGEST_PREFIX: &str = "sha256:";
39const DIGEST_HEX_LEN: usize = 64;
40const MAX_ID_BYTES: usize = 256;
41const MAX_MESSAGES: usize = 1_024;
42const MAX_PARTS: usize = 1_024;
43const MAX_PARTS_PER_MESSAGE: usize = 256;
44const MAX_HISTORY: usize = 2_048;
45const MAX_METADATA_ENTRIES: usize = 256;
46const MAX_TEXT_BYTES: usize = 1024 * 1024;
47const MAX_METADATA_VALUE_BYTES: usize = 64 * 1024;
48
49pub const TASK_DESCRIPTOR_VERSION: u32 = 1;
50pub const TASK_STATUS_VERSION: u32 = 1;
51pub const ARTIFACT_REF_VERSION: u32 = 1;
52pub const CAPABILITY_GRANT_REF_VERSION: u32 = 1;
53pub const TASK_AUTHORITY_CONFIG_VERSION: u32 = 1;
54pub const TASK_ACTION_SEND: &str = "tasks/send";
55pub const TASK_ACTION_GET: &str = "tasks/get";
56pub const TASK_ACTION_CANCEL: &str = "tasks/cancel";
57pub const TASK_CONTROL_DESCRIPTOR_VERSION: u32 = 1;
58
59mod authority;
60mod model;
61mod store;
62
63pub use authority::{
64    AgentArtifactRefV1, CapabilityGrantRefV1, TaskAuthorityConfigV1, TaskAuthorityError,
65    TaskAuthorityExpectationV1, TaskCapabilityGrantV1, TaskControlDescriptorV1, TaskDescriptorV1,
66    TaskPeerTrustV1, TaskScopeV1,
67};
68pub(crate) use model::{REASON_CANCELED_VIA_A2A, REASON_INPUT_RECEIVED};
69pub use model::{Task, TaskMessage, TaskPart, TaskState, TaskStatusV1, TaskTransition};
70pub use store::{RemoteTaskMaterialization, TaskStore};
71
72use authority::{AuthorityClaimV1, authorize, validate_digest, validate_identifier};
73
74#[cfg(test)]
75#[path = "task/tests.rs"]
76mod tests;
77
78#[cfg(test)]
79#[path = "task/gateway_tests.rs"]
80mod gateway_tests;
81
82#[cfg(test)]
83#[path = "task/authority_tests.rs"]
84mod authority_tests;