Skip to main content

mur_common/
a2a.rs

1//! A2A v0.3 protocol envelope types.
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Message {
6    pub role: String, // "user" | "agent" | "system"
7    pub parts: Vec<MessagePart>,
8}
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(tag = "kind", rename_all = "lowercase")]
12pub enum MessagePart {
13    Text {
14        text: String,
15    },
16    Data {
17        #[serde(rename = "mimeType")]
18        mime_type: String,
19        data: serde_json::Value,
20    },
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
24#[serde(rename_all = "lowercase")]
25pub enum TaskState {
26    Submitted,
27    Working,
28    Completed,
29    Failed,
30    Cancelled,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Task {
35    pub id: String,
36    pub state: TaskState,
37    pub messages: Vec<Message>,
38    #[serde(rename = "createdAt")]
39    pub created_at: String,
40    #[serde(rename = "completedAt", skip_serializing_if = "Option::is_none")]
41    pub completed_at: Option<String>,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub error: Option<TaskError>,
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub usage: Option<serde_json::Value>,
46    /// Zero or more file artifacts produced by this task. Present when the
47    /// task completed with an `output_artifact_path` — the consumer reads
48    /// these files byte-by-byte instead of re-typing inline content through
49    /// another LLM (#715 Part B).
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub artifacts: Option<Vec<ArtifactInfo>>,
52}
53
54/// Metadata for an artifact produced by a task — a file the agent wrote to
55/// a known path so callers can read it byte-by-byte instead of re-typing the
56/// content through another LLM (issue #715 Part B).
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct ArtifactInfo {
59    /// Absolute path the artifact was written to.
60    pub path: String,
61    /// MIME type (e.g. "text/markdown", "application/json").
62    #[serde(rename = "mimeType")]
63    pub mime_type: String,
64    /// SHA-256 hex digest of the file content, for integrity checking by the
65    /// consumer before they use it. Always present when the runtime verified
66    /// the file post-completion.
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub sha256: Option<String>,
69    /// File size in bytes.
70    pub size_bytes: u64,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct TaskError {
75    pub code: String,
76    pub message: String,
77    pub recoverable: bool,
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub details: Option<serde_json::Value>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct JsonRpcRequest {
84    pub jsonrpc: String, // always "2.0"
85    #[serde(default, skip_serializing_if = "Option::is_none")]
86    pub id: Option<serde_json::Value>, // None = notification
87    pub method: String,
88    #[serde(default, skip_serializing_if = "Option::is_none")]
89    pub params: Option<serde_json::Value>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct JsonRpcResponse {
94    pub jsonrpc: String, // "2.0"
95    pub id: serde_json::Value,
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub result: Option<serde_json::Value>,
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub error: Option<JsonRpcError>,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct JsonRpcError {
104    pub code: i32,
105    pub message: String,
106    #[serde(default, skip_serializing_if = "Option::is_none")]
107    pub data: Option<serde_json::Value>,
108}