systemprompt_models/a2a/agent_card/
extension.rs1use 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_string(),
63 description: Some("MCP tool execution capabilities".to_string()),
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 mcp_tools_extension_with_servers(servers: &[serde_json::Value]) -> Self {
73 Self {
74 uri: "systemprompt:mcp-tools".to_string(),
75 description: Some("MCP tool execution capabilities with server endpoints".to_string()),
76 required: Some(false),
77 params: Some(serde_json::json!({
78 "supported_protocols": ["mcp-1.0"],
79 "servers": servers
80 })),
81 }
82 }
83
84 #[must_use]
85 pub fn opencode_integration_extension() -> Self {
86 Self {
87 uri: "systemprompt:opencode-integration".to_string(),
88 description: Some("OpenCode AI reasoning integration".to_string()),
89 required: Some(false),
90 params: Some(serde_json::json!({
91 "reasoning_model": "claude-3-5-sonnet",
92 "execution_mode": "structured_planning"
93 })),
94 }
95 }
96
97 #[must_use]
98 pub fn artifact_rendering_extension() -> Self {
99 Self {
100 uri: ARTIFACT_RENDERING_URI.to_string(),
101 description: Some(
102 "MCP tool results rendered as typed artifacts with UI hints".to_string(),
103 ),
104 required: Some(false),
105 params: Some(serde_json::json!({
106 "supported_types": ["table", "form", "chart", "tree", "code", "json", "markdown"],
107 "version": "1.0.0"
108 })),
109 }
110 }
111
112 #[must_use]
113 pub fn agent_identity(agent_name: &str) -> Self {
114 Self {
115 uri: "systemprompt:agent-identity".to_string(),
116 description: Some("systemprompt.io platform agent name".to_string()),
117 required: Some(true),
118 params: Some(serde_json::json!({
119 "name": agent_name
120 })),
121 }
122 }
123
124 #[must_use]
125 pub fn system_instructions(system_prompt: &str) -> Self {
126 Self {
127 uri: "systemprompt:system-instructions".to_string(),
128 description: Some("Agent system prompt and behavioral guidelines".to_string()),
129 required: Some(true),
130 params: Some(serde_json::json!({
131 "systemPrompt": system_prompt,
132 "format": "text/plain"
133 })),
134 }
135 }
136
137 #[must_use]
138 pub fn system_instructions_opt(system_prompt: Option<&str>) -> Option<Self> {
139 system_prompt.map(Self::system_instructions)
140 }
141
142 #[must_use]
143 pub fn service_status(
144 status: &str,
145 port: Option<u16>,
146 pid: Option<u32>,
147 default: bool,
148 ) -> Self {
149 let mut params = serde_json::json!({
150 "status": status,
151 "default": default
152 });
153
154 if let Some(p) = port {
155 params["port"] = serde_json::json!(p);
156 }
157 if let Some(p) = pid {
158 params["pid"] = serde_json::json!(p);
159 }
160
161 Self {
162 uri: "systemprompt:service-status".to_string(),
163 description: Some("Runtime service status from orchestrator".to_string()),
164 required: Some(true),
165 params: Some(params),
166 }
167 }
168}