1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
11#[serde(rename_all = "camelCase")]
12pub enum ElicitationAction {
13 Accept,
15 Decline,
17 Cancel,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct ElicitationSchema {
24 #[serde(rename = "type")]
26 pub schema_type: String,
27 pub properties: HashMap<String, PrimitiveSchemaDefinition>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub required: Option<Vec<String>>,
32 #[serde(
34 rename = "additionalProperties",
35 skip_serializing_if = "Option::is_none"
36 )]
37 pub additional_properties: Option<bool>,
38}
39
40impl ElicitationSchema {
41 pub fn new() -> Self {
43 Self {
44 schema_type: "object".to_string(),
45 properties: HashMap::new(),
46 required: Some(Vec::new()),
47 additional_properties: Some(false),
48 }
49 }
50
51 pub fn add_string_property(
53 mut self,
54 name: String,
55 required: bool,
56 description: Option<String>,
57 ) -> Self {
58 let property = PrimitiveSchemaDefinition::String {
59 title: None,
60 description,
61 format: None,
62 min_length: None,
63 max_length: None,
64 enum_values: None,
65 enum_names: None,
66 };
67
68 self.properties.insert(name.clone(), property);
69
70 if required && let Some(ref mut required_fields) = self.required {
71 required_fields.push(name);
72 }
73
74 self
75 }
76
77 pub fn add_number_property(
79 mut self,
80 name: String,
81 required: bool,
82 description: Option<String>,
83 minimum: Option<f64>,
84 maximum: Option<f64>,
85 ) -> Self {
86 let property = PrimitiveSchemaDefinition::Number {
87 title: None,
88 description,
89 minimum,
90 maximum,
91 };
92
93 self.properties.insert(name.clone(), property);
94
95 if required && let Some(ref mut required_fields) = self.required {
96 required_fields.push(name);
97 }
98
99 self
100 }
101
102 pub fn add_boolean_property(
104 mut self,
105 name: String,
106 required: bool,
107 description: Option<String>,
108 default: Option<bool>,
109 ) -> Self {
110 let property = PrimitiveSchemaDefinition::Boolean {
111 title: None,
112 description,
113 default,
114 };
115
116 self.properties.insert(name.clone(), property);
117
118 if required && let Some(ref mut required_fields) = self.required {
119 required_fields.push(name);
120 }
121
122 self
123 }
124}
125
126impl Default for ElicitationSchema {
127 fn default() -> Self {
128 Self::new()
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134#[serde(tag = "type")]
135pub enum PrimitiveSchemaDefinition {
136 #[serde(rename = "string")]
138 String {
139 #[serde(skip_serializing_if = "Option::is_none")]
141 title: Option<String>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 description: Option<String>,
145 #[serde(skip_serializing_if = "Option::is_none")]
147 format: Option<String>,
148 #[serde(skip_serializing_if = "Option::is_none")]
150 #[serde(rename = "minLength")]
151 min_length: Option<u32>,
152 #[serde(skip_serializing_if = "Option::is_none")]
154 #[serde(rename = "maxLength")]
155 max_length: Option<u32>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 #[serde(rename = "enum")]
159 enum_values: Option<Vec<String>>,
160 #[serde(skip_serializing_if = "Option::is_none")]
162 #[serde(rename = "enumNames")]
163 enum_names: Option<Vec<String>>,
164 },
165 #[serde(rename = "number")]
167 Number {
168 #[serde(skip_serializing_if = "Option::is_none")]
170 title: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
173 description: Option<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 minimum: Option<f64>,
177 #[serde(skip_serializing_if = "Option::is_none")]
179 maximum: Option<f64>,
180 },
181 #[serde(rename = "integer")]
183 Integer {
184 #[serde(skip_serializing_if = "Option::is_none")]
186 title: Option<String>,
187 #[serde(skip_serializing_if = "Option::is_none")]
189 description: Option<String>,
190 #[serde(skip_serializing_if = "Option::is_none")]
192 minimum: Option<i64>,
193 #[serde(skip_serializing_if = "Option::is_none")]
195 maximum: Option<i64>,
196 },
197 #[serde(rename = "boolean")]
199 Boolean {
200 #[serde(skip_serializing_if = "Option::is_none")]
202 title: Option<String>,
203 #[serde(skip_serializing_if = "Option::is_none")]
205 description: Option<String>,
206 #[serde(skip_serializing_if = "Option::is_none")]
208 default: Option<bool>,
209 },
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct ElicitRequestParams {
215 pub message: String,
217 #[serde(rename = "requestedSchema")]
219 pub schema: ElicitationSchema,
220 #[serde(rename = "timeoutMs", skip_serializing_if = "Option::is_none")]
222 pub timeout_ms: Option<u32>,
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub cancellable: Option<bool>,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct ElicitRequest {
231 #[serde(flatten)]
233 pub params: ElicitRequestParams,
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub _meta: Option<serde_json::Value>,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct ElicitResult {
242 pub action: ElicitationAction,
244 #[serde(skip_serializing_if = "Option::is_none")]
246 pub content: Option<std::collections::HashMap<String, serde_json::Value>>,
247 #[serde(skip_serializing_if = "Option::is_none")]
249 pub _meta: Option<serde_json::Value>,
250}