1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "kebab-case")]
11pub enum TaskState {
12 Submitted,
13 Working,
14 Completed,
15 Failed,
16 Cancelled,
17 InputRequired,
18 Rejected,
19 AuthRequired,
20}
21
22impl TaskState {
23 pub fn is_terminal(&self) -> bool {
25 matches!(
26 self,
27 TaskState::Completed | TaskState::Failed | TaskState::Cancelled | TaskState::Rejected
28 )
29 }
30
31 pub fn is_active(&self) -> bool {
33 !self.is_terminal()
34 }
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct Task {
41 pub id: String,
42 pub context_id: Option<String>,
43 pub status: TaskStatus,
44 #[serde(default)]
45 pub artifacts: Vec<Artifact>,
46 #[serde(default)]
47 pub history: Vec<Message>,
48 #[serde(default)]
49 pub metadata: HashMap<String, serde_json::Value>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54#[serde(rename_all = "camelCase")]
55pub struct TaskStatus {
56 pub state: TaskState,
57 #[serde(default)]
58 pub message: Option<Message>,
59 pub timestamp: Option<String>,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct Message {
66 pub message_id: String,
67 pub role: MessageRole,
68 pub parts: Vec<Part>,
69 #[serde(default)]
70 pub context_id: Option<String>,
71 #[serde(default)]
72 pub task_id: Option<String>,
73 #[serde(default)]
74 pub metadata: HashMap<String, serde_json::Value>,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(rename_all = "lowercase")]
79pub enum MessageRole {
80 User,
81 Agent,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(tag = "kind", rename_all = "camelCase")]
87pub enum Part {
88 #[serde(rename = "text")]
89 Text { text: String },
90 #[serde(rename = "file")]
91 File { file: FileContent },
92 #[serde(rename = "data")]
93 Data { data: serde_json::Value },
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct FileContent {
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub bytes: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
103 pub uri: Option<String>,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub mime_type: Option<String>,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 pub name: Option<String>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct Artifact {
114 pub artifact_id: String,
115 pub parts: Vec<Part>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub name: Option<String>,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub description: Option<String>,
120 #[serde(default)]
121 pub metadata: HashMap<String, serde_json::Value>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct AgentCard {
128 pub name: String,
129 pub description: String,
130 pub url: String,
131 pub version: String,
132 #[serde(default = "default_protocol_version")]
133 pub protocol_version: String,
134 pub capabilities: AgentCapabilities,
135 pub skills: Vec<AgentSkill>,
136 #[serde(default)]
137 pub default_input_modes: Vec<String>,
138 #[serde(default)]
139 pub default_output_modes: Vec<String>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub provider: Option<AgentProvider>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub icon_url: Option<String>,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub documentation_url: Option<String>,
146}
147
148fn default_protocol_version() -> String {
149 "0.3.0".to_string()
150}
151
152#[derive(Debug, Clone, Default, Serialize, Deserialize)]
153#[serde(rename_all = "camelCase")]
154pub struct AgentCapabilities {
155 #[serde(default)]
156 pub streaming: bool,
157 #[serde(default)]
158 pub push_notifications: bool,
159 #[serde(default)]
160 pub state_transition_history: bool,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
164#[serde(rename_all = "camelCase")]
165pub struct AgentSkill {
166 pub id: String,
167 pub name: String,
168 pub description: String,
169 #[serde(default)]
170 pub tags: Vec<String>,
171 #[serde(default)]
172 pub examples: Vec<String>,
173 #[serde(default)]
174 pub input_modes: Vec<String>,
175 #[serde(default)]
176 pub output_modes: Vec<String>,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct AgentProvider {
181 pub organization: String,
182 pub url: String,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct JsonRpcRequest {
188 pub jsonrpc: String,
189 pub id: serde_json::Value,
190 pub method: String,
191 #[serde(default)]
192 pub params: serde_json::Value,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct JsonRpcResponse {
198 pub jsonrpc: String,
199 pub id: serde_json::Value,
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub result: Option<serde_json::Value>,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub error: Option<JsonRpcError>,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct JsonRpcError {
208 pub code: i32,
209 pub message: String,
210 #[serde(skip_serializing_if = "Option::is_none")]
211 pub data: Option<serde_json::Value>,
212}
213
214#[allow(dead_code)]
215impl JsonRpcError {
216 pub fn parse_error(msg: impl Into<String>) -> Self {
218 Self {
219 code: PARSE_ERROR,
220 message: msg.into(),
221 data: None,
222 }
223 }
224
225 pub fn invalid_request(msg: impl Into<String>) -> Self {
227 Self {
228 code: INVALID_REQUEST,
229 message: msg.into(),
230 data: None,
231 }
232 }
233
234 pub fn method_not_found(method: &str) -> Self {
236 Self {
237 code: METHOD_NOT_FOUND,
238 message: format!("Method not found: {}", method),
239 data: None,
240 }
241 }
242
243 pub fn invalid_params(msg: impl Into<String>) -> Self {
245 Self {
246 code: INVALID_PARAMS,
247 message: msg.into(),
248 data: None,
249 }
250 }
251
252 pub fn internal_error(msg: impl Into<String>) -> Self {
254 Self {
255 code: INTERNAL_ERROR,
256 message: msg.into(),
257 data: None,
258 }
259 }
260}
261
262#[allow(dead_code)]
264pub const PARSE_ERROR: i32 = -32700;
265#[allow(dead_code)]
266pub const INVALID_REQUEST: i32 = -32600;
267pub const METHOD_NOT_FOUND: i32 = -32601;
268pub const INVALID_PARAMS: i32 = -32602;
269pub const INTERNAL_ERROR: i32 = -32603;
270
271pub const TASK_NOT_FOUND: i32 = -32001;
273pub const TASK_NOT_CANCELABLE: i32 = -32002;
274#[allow(dead_code)]
275pub const PUSH_NOT_SUPPORTED: i32 = -32003;
276pub const UNSUPPORTED_OPERATION: i32 = -32004;
277#[allow(dead_code)]
278pub const CONTENT_TYPE_NOT_SUPPORTED: i32 = -32005;
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
282#[serde(rename_all = "camelCase")]
283pub struct MessageSendParams {
284 pub message: Message,
285 #[serde(skip_serializing_if = "Option::is_none")]
286 pub configuration: Option<MessageSendConfiguration>,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
290#[serde(rename_all = "camelCase")]
291pub struct MessageSendConfiguration {
292 #[serde(default)]
293 pub accepted_output_modes: Vec<String>,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub blocking: Option<bool>,
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub history_length: Option<usize>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub push_notification_config: Option<PushNotificationConfig>,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
303#[serde(rename_all = "camelCase")]
304pub struct PushNotificationConfig {
305 pub url: String,
306 #[serde(skip_serializing_if = "Option::is_none")]
307 pub token: Option<String>,
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub id: Option<String>,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize)]
314#[serde(rename_all = "camelCase")]
315pub struct TaskQueryParams {
316 pub id: String,
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub history_length: Option<usize>,
319}