use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum TaskState {
Submitted,
Working,
Completed,
Failed,
Cancelled,
InputRequired,
Rejected,
AuthRequired,
}
impl TaskState {
pub fn is_terminal(&self) -> bool {
matches!(
self,
TaskState::Completed | TaskState::Failed | TaskState::Cancelled | TaskState::Rejected
)
}
pub fn is_active(&self) -> bool {
!self.is_terminal()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Task {
pub id: String,
pub context_id: Option<String>,
pub status: TaskStatus,
#[serde(default)]
pub artifacts: Vec<Artifact>,
#[serde(default)]
pub history: Vec<Message>,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskStatus {
pub state: TaskState,
#[serde(default)]
pub message: Option<Message>,
pub timestamp: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Message {
pub message_id: String,
pub role: MessageRole,
pub parts: Vec<Part>,
#[serde(default)]
pub context_id: Option<String>,
#[serde(default)]
pub task_id: Option<String>,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub extensions: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MessageRole {
User,
Agent,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum Part {
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "file")]
File { file: FileContent },
#[serde(rename = "data")]
Data { data: serde_json::Value },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FileContent {
#[serde(skip_serializing_if = "Option::is_none")]
pub bytes: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
pub uri: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Artifact {
pub artifact_id: String,
pub parts: Vec<Part>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub extensions: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentCard {
pub name: String,
pub description: String,
pub url: String,
pub version: String,
#[serde(default = "default_protocol_version")]
pub protocol_version: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub preferred_transport: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub additional_interfaces: Vec<AgentInterface>,
pub capabilities: AgentCapabilities,
pub skills: Vec<AgentSkill>,
#[serde(default)]
pub default_input_modes: Vec<String>,
#[serde(default)]
pub default_output_modes: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<AgentProvider>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub documentation_url: Option<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub security_schemes: HashMap<String, SecurityScheme>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub security: Vec<SecurityRequirement>,
#[serde(default)]
pub supports_authenticated_extended_card: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub signatures: Vec<AgentCardSignature>,
}
fn default_protocol_version() -> String {
"0.3.0".to_string()
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentCapabilities {
#[serde(default)]
pub streaming: bool,
#[serde(default)]
pub push_notifications: bool,
#[serde(default)]
pub state_transition_history: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub extensions: Vec<AgentExtension>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentSkill {
pub id: String,
pub name: String,
pub description: String,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub examples: Vec<String>,
#[serde(default)]
pub input_modes: Vec<String>,
#[serde(default)]
pub output_modes: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentProvider {
pub organization: String,
pub url: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcRequest {
pub jsonrpc: String,
pub id: serde_json::Value,
pub method: String,
#[serde(default)]
pub params: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcResponse {
pub jsonrpc: String,
pub id: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<JsonRpcError>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcError {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
}
#[allow(dead_code)]
impl JsonRpcError {
pub fn parse_error(msg: impl Into<String>) -> Self {
Self {
code: PARSE_ERROR,
message: msg.into(),
data: None,
}
}
pub fn invalid_request(msg: impl Into<String>) -> Self {
Self {
code: INVALID_REQUEST,
message: msg.into(),
data: None,
}
}
pub fn method_not_found(method: &str) -> Self {
Self {
code: METHOD_NOT_FOUND,
message: format!("Method not found: {}", method),
data: None,
}
}
pub fn invalid_params(msg: impl Into<String>) -> Self {
Self {
code: INVALID_PARAMS,
message: msg.into(),
data: None,
}
}
pub fn internal_error(msg: impl Into<String>) -> Self {
Self {
code: INTERNAL_ERROR,
message: msg.into(),
data: None,
}
}
pub fn unsupported_operation(msg: impl Into<String>) -> Self {
Self {
code: UNSUPPORTED_OPERATION,
message: msg.into(),
data: None,
}
}
}
#[allow(dead_code)]
pub const PARSE_ERROR: i32 = -32700;
#[allow(dead_code)]
pub const INVALID_REQUEST: i32 = -32600;
pub const METHOD_NOT_FOUND: i32 = -32601;
pub const INVALID_PARAMS: i32 = -32602;
pub const INTERNAL_ERROR: i32 = -32603;
pub const TASK_NOT_FOUND: i32 = -32001;
pub const TASK_NOT_CANCELABLE: i32 = -32002;
#[allow(dead_code)]
pub const PUSH_NOT_SUPPORTED: i32 = -32003;
pub const UNSUPPORTED_OPERATION: i32 = -32004;
#[allow(dead_code)]
pub const CONTENT_TYPE_NOT_SUPPORTED: i32 = -32005;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MessageSendParams {
pub message: Message,
#[serde(skip_serializing_if = "Option::is_none")]
pub configuration: Option<MessageSendConfiguration>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MessageSendConfiguration {
#[serde(default)]
pub accepted_output_modes: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub blocking: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub history_length: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub push_notification_config: Option<PushNotificationConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PushNotificationConfig {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskQueryParams {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub history_length: Option<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskStatusUpdateEvent {
pub id: String,
pub status: TaskStatus,
#[serde(default, rename = "final")]
pub is_final: bool,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskArtifactUpdateEvent {
pub id: String,
pub artifact: Artifact,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StreamEvent {
StatusUpdate(TaskStatusUpdateEvent),
ArtifactUpdate(TaskArtifactUpdateEvent),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SendMessageResponse {
Task(Task),
Message(Message),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum SecurityScheme {
#[serde(rename = "apiKey")]
ApiKey {
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
name: String,
#[serde(rename = "in")]
location: String, },
#[serde(rename = "http")]
Http {
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
scheme: String,
#[serde(skip_serializing_if = "Option::is_none")]
bearer_format: Option<String>,
},
#[serde(rename = "oauth2")]
OAuth2 {
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
flows: OAuthFlows,
},
#[serde(rename = "openIdConnect")]
OpenIdConnect {
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
open_id_connect_url: String,
},
#[serde(rename = "mutualTLS")]
MutualTls {
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
},
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OAuthFlows {
#[serde(skip_serializing_if = "Option::is_none")]
pub implicit: Option<OAuthFlowImplicit>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authorization_code: Option<OAuthFlowAuthorizationCode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_credentials: Option<OAuthFlowClientCredentials>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_code: Option<OAuthFlowDeviceCode>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OAuthFlowImplicit {
pub authorization_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_url: Option<String>,
#[serde(default)]
pub scopes: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OAuthFlowAuthorizationCode {
pub authorization_url: String,
pub token_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_url: Option<String>,
#[serde(default)]
pub scopes: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OAuthFlowClientCredentials {
pub token_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_url: Option<String>,
#[serde(default)]
pub scopes: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OAuthFlowDeviceCode {
pub device_authorization_url: String,
pub token_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_url: Option<String>,
#[serde(default)]
pub scopes: HashMap<String, String>,
}
pub type SecurityRequirement = HashMap<String, Vec<String>>;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentExtension {
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default)]
pub required: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub params: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentCardSignature {
pub signature: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub algorithm: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub key_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentInterface {
pub transport: String,
pub url: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub content_types: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskPushNotificationConfig {
pub id: String, pub push_notification_config: PushNotificationConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthenticationInfo {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub schemes: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub credentials: Option<String>,
}