fix(examples): accept stringified prompt argument values (#859)
This commit is contained in:
parent
53e4410d99
commit
6a7f10af51
1 changed files with 48 additions and 0 deletions
|
|
@ -44,9 +44,29 @@ pub struct ExamplePromptArgs {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// MCP spec types prompt arguments as `Record<string, string>`, so
|
||||||
|
/// spec-compliant clients stringify all values. Accept both wire forms.
|
||||||
|
fn deserialize_i32_from_string_or_int<'de, D>(deserializer: D) -> Result<i32, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
use serde::Deserialize;
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum StringOrInt {
|
||||||
|
Int(i32),
|
||||||
|
Str(String),
|
||||||
|
}
|
||||||
|
match StringOrInt::deserialize(deserializer)? {
|
||||||
|
StringOrInt::Int(n) => Ok(n),
|
||||||
|
StringOrInt::Str(s) => s.parse::<i32>().map_err(serde::de::Error::custom),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
|
||||||
pub struct CounterAnalysisArgs {
|
pub struct CounterAnalysisArgs {
|
||||||
/// The target value you're trying to reach
|
/// The target value you're trying to reach
|
||||||
|
#[serde(deserialize_with = "deserialize_i32_from_string_or_int")]
|
||||||
pub goal: i32,
|
pub goal: i32,
|
||||||
/// Preferred strategy: 'fast' or 'careful'
|
/// Preferred strategy: 'fast' or 'careful'
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
|
@ -334,6 +354,34 @@ mod tests {
|
||||||
assert_eq!(args[1].required, Some(false));
|
assert_eq!(args[1].required, Some(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_counter_analysis_args_accepts_integer_goal() {
|
||||||
|
let json = serde_json::json!({ "goal": 20 });
|
||||||
|
let args: CounterAnalysisArgs = serde_json::from_value(json).unwrap();
|
||||||
|
assert_eq!(args.goal, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_counter_analysis_args_accepts_string_goal() {
|
||||||
|
let json = serde_json::json!({ "goal": "20" });
|
||||||
|
let args: CounterAnalysisArgs = serde_json::from_value(json).unwrap();
|
||||||
|
assert_eq!(args.goal, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_counter_analysis_args_accepts_negative_string_goal() {
|
||||||
|
let json = serde_json::json!({ "goal": "-7" });
|
||||||
|
let args: CounterAnalysisArgs = serde_json::from_value(json).unwrap();
|
||||||
|
assert_eq!(args.goal, -7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_counter_analysis_args_rejects_non_numeric_string_goal() {
|
||||||
|
let json = serde_json::json!({ "goal": "not a number" });
|
||||||
|
let result: Result<CounterAnalysisArgs, _> = serde_json::from_value(json);
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_prompt_router_has_routes() {
|
async fn test_prompt_router_has_routes() {
|
||||||
let router = Counter::prompt_router();
|
let router = Counter::prompt_router();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue