use crate::{
ElicitCommunicator, ElicitError, ElicitErrorKind, ElicitResult, Elicitation, Prompt, Select,
mcp,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DateTimeInputMethod {
Iso8601String,
ManualComponents,
}
impl crate::Prompt for DateTimeInputMethod {
fn prompt() -> Option<&'static str> {
Some("How would you like to enter the datetime?")
}
}
impl Select for DateTimeInputMethod {
fn options() -> Vec<Self> {
vec![
DateTimeInputMethod::Iso8601String,
DateTimeInputMethod::ManualComponents,
]
}
fn labels() -> Vec<String> {
vec![
"ISO 8601 string (e.g., \"2024-07-11T15:30:00Z\")".to_string(),
"Manual components (year, month, day, etc.)".to_string(),
]
}
fn from_label(label: &str) -> Option<Self> {
if label.contains("ISO") || label.contains("string") {
Some(DateTimeInputMethod::Iso8601String)
} else if label.contains("Manual") || label.contains("components") {
Some(DateTimeInputMethod::ManualComponents)
} else {
None
}
}
}
crate::default_style!(DateTimeInputMethod => DateTimeInputMethodStyle);
impl Elicitation for DateTimeInputMethod {
type Style = DateTimeInputMethodStyle;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
let prompt = Self::prompt().unwrap();
tracing::debug!("Eliciting datetime input method");
let params = mcp::select_params(prompt, &Self::labels());
let result = communicator
.call_tool(rmcp::model::CallToolRequestParams {
meta: None,
name: mcp::tool_names::elicit_select().into(),
arguments: Some(params),
task: None,
})
.await?;
let value = mcp::extract_value(result)?;
let label = mcp::parse_string(value)?;
Self::from_label(&label)
.ok_or_else(|| ElicitError::new(ElicitErrorKind::InvalidSelection(label)))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DateTimeComponents {
pub year: i32,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
}
impl DateTimeComponents {
#[tracing::instrument(skip(communicator))]
pub async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting datetime components");
let year_params = mcp::number_params("Enter year:", 1970, 2100);
let year_result = communicator
.call_tool(rmcp::model::CallToolRequestParams {
meta: None,
name: mcp::tool_names::elicit_number().into(),
arguments: Some(year_params),
task: None,
})
.await?;
let year_value = mcp::extract_value(year_result)?;
let year = mcp::parse_integer::<i64>(year_value)? as i32;
let month_params = mcp::number_params("Enter month (1-12):", 1, 12);
let month_result = communicator
.call_tool(rmcp::model::CallToolRequestParams {
meta: None,
name: mcp::tool_names::elicit_number().into(),
arguments: Some(month_params),
task: None,
})
.await?;
let month_value = mcp::extract_value(month_result)?;
let month = mcp::parse_integer::<i64>(month_value)? as u8;
let day_params = mcp::number_params("Enter day (1-31):", 1, 31);
let day_result = communicator
.call_tool(rmcp::model::CallToolRequestParams {
meta: None,
name: mcp::tool_names::elicit_number().into(),
arguments: Some(day_params),
task: None,
})
.await?;
let day_value = mcp::extract_value(day_result)?;
let day = mcp::parse_integer::<i64>(day_value)? as u8;
let hour_params = mcp::number_params("Enter hour (0-23):", 0, 23);
let hour_result = communicator
.call_tool(rmcp::model::CallToolRequestParams {
meta: None,
name: mcp::tool_names::elicit_number().into(),
arguments: Some(hour_params),
task: None,
})
.await?;
let hour_value = mcp::extract_value(hour_result)?;
let hour = mcp::parse_integer::<i64>(hour_value)? as u8;
let minute_params = mcp::number_params("Enter minute (0-59):", 0, 59);
let minute_result = communicator
.call_tool(rmcp::model::CallToolRequestParams {
meta: None,
name: mcp::tool_names::elicit_number().into(),
arguments: Some(minute_params),
task: None,
})
.await?;
let minute_value = mcp::extract_value(minute_result)?;
let minute = mcp::parse_integer::<i64>(minute_value)? as u8;
let second_params = mcp::number_params("Enter second (0-59):", 0, 59);
let second_result = communicator
.call_tool(rmcp::model::CallToolRequestParams {
meta: None,
name: mcp::tool_names::elicit_number().into(),
arguments: Some(second_params),
task: None,
})
.await?;
let second_value = mcp::extract_value(second_result)?;
let second = mcp::parse_integer::<i64>(second_value)? as u8;
tracing::debug!(
year,
month,
day,
hour,
minute,
second,
"Components elicited"
);
Ok(Self {
year,
month,
day,
hour,
minute,
second,
})
}
}