use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct QuestionRequest {
pub id: String,
pub session_id: String,
pub questions: Vec<QuestionInfo>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tool: Option<QuestionToolContext>,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct QuestionInfo {
pub question: String,
#[serde(default)]
pub header: String,
#[serde(default)]
pub options: Vec<QuestionOption>,
#[serde(default)]
pub multiple: bool,
#[serde(default = "default_true")]
pub custom: bool,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct QuestionOption {
pub label: String,
#[serde(default)]
pub description: String,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct QuestionToolContext {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub message_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub call_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct QuestionReply {
pub answers: Vec<Vec<String>>,
}
fn default_true() -> bool {
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_question_request_minimal() {
let json = r#"{
"id": "req-123",
"sessionId": "sess-456",
"questions": []
}"#;
let req: QuestionRequest = serde_json::from_str(json).unwrap();
assert_eq!(req.id, "req-123");
assert_eq!(req.session_id, "sess-456");
assert!(req.questions.is_empty());
assert!(req.tool.is_none());
}
#[test]
fn test_question_request_full() {
let json = r#"{
"id": "req-123",
"sessionId": "sess-456",
"questions": [
{
"question": "What do you want to do?",
"header": "Choose an action",
"options": [
{"label": "Save", "description": "Save the file"},
{"label": "Discard", "description": "Discard changes"}
],
"multiple": false,
"custom": true
}
],
"tool": {
"messageId": "msg-1",
"callId": "call-1",
"name": "confirm"
}
}"#;
let req: QuestionRequest = serde_json::from_str(json).unwrap();
assert_eq!(req.id, "req-123");
assert_eq!(req.questions.len(), 1);
let q = &req.questions[0];
assert_eq!(q.question, "What do you want to do?");
assert_eq!(q.header, "Choose an action");
assert_eq!(q.options.len(), 2);
assert!(!q.multiple);
assert!(q.custom);
let tool = req.tool.unwrap();
assert_eq!(tool.message_id, Some("msg-1".to_string()));
assert_eq!(tool.name, Some("confirm".to_string()));
}
#[test]
fn test_question_info_defaults() {
let json = r#"{"question": "Continue?"}"#;
let info: QuestionInfo = serde_json::from_str(json).unwrap();
assert_eq!(info.question, "Continue?");
assert!(info.header.is_empty());
assert!(info.options.is_empty());
assert!(!info.multiple);
assert!(info.custom); }
#[test]
fn test_question_option() {
let json = r#"{"label": "Yes", "description": "Confirm action"}"#;
let opt: QuestionOption = serde_json::from_str(json).unwrap();
assert_eq!(opt.label, "Yes");
assert_eq!(opt.description, "Confirm action");
}
#[test]
fn test_question_reply() {
let reply = QuestionReply {
answers: vec![vec!["Save".to_string()]],
};
let json = serde_json::to_string(&reply).unwrap();
assert!(json.contains("Save"));
let parsed: QuestionReply = serde_json::from_str(&json).unwrap();
assert_eq!(parsed.answers.len(), 1);
assert_eq!(parsed.answers[0], vec!["Save"]);
}
#[test]
fn test_question_reply_multiple() {
let json = r#"{"answers": [["A", "B"], ["C"]]}"#;
let reply: QuestionReply = serde_json::from_str(json).unwrap();
assert_eq!(reply.answers.len(), 2);
assert_eq!(reply.answers[0], vec!["A", "B"]);
assert_eq!(reply.answers[1], vec!["C"]);
}
#[test]
fn test_question_extra_fields_preserved() {
let json = r#"{
"id": "req-123",
"sessionId": "sess-456",
"questions": [],
"futureField": "value"
}"#;
let req: QuestionRequest = serde_json::from_str(json).unwrap();
assert_eq!(req.extra["futureField"], "value");
}
}