Skip to main content

systemprompt_models/a2a/agent_card/
extension.rs

1//! Agent capability flags and the named extension catalogue.
2
3use serde::{Deserialize, Serialize};
4
5pub const ARTIFACT_RENDERING_URI: &str = "https://systemprompt.io/extensions/artifact-rendering/v1";
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(rename_all = "camelCase")]
9pub struct AgentCapabilities {
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub streaming: Option<bool>,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub push_notifications: Option<bool>,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub state_transition_history: Option<bool>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub extensions: Option<Vec<AgentExtension>>,
18}
19
20impl Default for AgentCapabilities {
21    fn default() -> Self {
22        Self {
23            streaming: Some(true),
24            push_notifications: Some(true),
25            state_transition_history: Some(true),
26            extensions: None,
27        }
28    }
29}
30
31impl AgentCapabilities {
32    #[must_use]
33    pub const fn normalize(mut self) -> Self {
34        if self.streaming.is_none() {
35            self.streaming = Some(true);
36        }
37        if self.push_notifications.is_none() {
38            self.push_notifications = Some(false);
39        }
40        if self.state_transition_history.is_none() {
41            self.state_transition_history = Some(true);
42        }
43        self
44    }
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
48pub struct AgentExtension {
49    pub uri: String,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub description: Option<String>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub required: Option<bool>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub params: Option<serde_json::Value>,
56}
57
58impl AgentExtension {
59    #[must_use]
60    pub fn mcp_tools_extension() -> Self {
61        Self {
62            uri: "systemprompt:mcp-tools".to_owned(),
63            description: Some("MCP tool execution capabilities".to_owned()),
64            required: Some(false),
65            params: Some(serde_json::json!({
66                "supported_protocols": ["mcp-1.0"]
67            })),
68        }
69    }
70
71    #[must_use]
72    pub fn agent_identity(agent_name: &str) -> Self {
73        Self {
74            uri: "systemprompt:agent-identity".to_owned(),
75            description: Some("systemprompt.io platform agent name".to_owned()),
76            required: Some(true),
77            params: Some(serde_json::json!({
78                "name": agent_name
79            })),
80        }
81    }
82
83    #[must_use]
84    pub fn system_instructions(system_prompt: &str) -> Self {
85        Self {
86            uri: "systemprompt:system-instructions".to_owned(),
87            description: Some("Agent system prompt and behavioral guidelines".to_owned()),
88            required: Some(true),
89            params: Some(serde_json::json!({
90                "systemPrompt": system_prompt,
91                "format": "text/plain"
92            })),
93        }
94    }
95
96    #[must_use]
97    pub fn system_instructions_opt(system_prompt: Option<&str>) -> Option<Self> {
98        system_prompt.map(Self::system_instructions)
99    }
100
101    #[must_use]
102    pub fn service_status(
103        status: &str,
104        port: Option<u16>,
105        pid: Option<u32>,
106        default: bool,
107    ) -> Self {
108        let mut params = serde_json::json!({
109            "status": status,
110            "default": default
111        });
112
113        if let Some(p) = port {
114            params["port"] = serde_json::json!(p);
115        }
116        if let Some(p) = pid {
117            params["pid"] = serde_json::json!(p);
118        }
119
120        Self {
121            uri: "systemprompt:service-status".to_owned(),
122            description: Some("Runtime service status from orchestrator".to_owned()),
123            required: Some(true),
124            params: Some(params),
125        }
126    }
127}