fix: default CallToolResult content to empty vec on missing field (#752)
This commit is contained in:
parent
66712db808
commit
44dfcf5550
4 changed files with 42 additions and 33 deletions
|
|
@ -2697,6 +2697,7 @@ pub type ElicitationCompletionNotification =
|
|||
#[non_exhaustive]
|
||||
pub struct CallToolResult {
|
||||
/// The content returned by the tool (text, images, etc.)
|
||||
#[serde(default)]
|
||||
pub content: Vec<Content>,
|
||||
/// An optional JSON object that represents the structured result of the tool call
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -3247,16 +3248,16 @@ ts_union!(
|
|||
| ListResourcesResult
|
||||
| ListResourceTemplatesResult
|
||||
| ReadResourceResult
|
||||
| CallToolResult
|
||||
| ListToolsResult
|
||||
| CreateElicitationResult
|
||||
| EmptyResult
|
||||
| CreateTaskResult
|
||||
| ListTasksResult
|
||||
| GetTaskResult
|
||||
| CancelTaskResult
|
||||
| CustomResult
|
||||
| CallToolResult
|
||||
| GetTaskPayloadResult
|
||||
| EmptyResult
|
||||
| CustomResult
|
||||
;
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@
|
|||
"content": {
|
||||
"description": "The content returned by the tool (text, images, etc.)",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/definitions/Annotated"
|
||||
}
|
||||
|
|
@ -402,10 +403,7 @@
|
|||
"structuredContent": {
|
||||
"description": "An optional JSON object that represents the structured result of the tool call"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"content"
|
||||
]
|
||||
}
|
||||
},
|
||||
"CancelTaskResult": {
|
||||
"description": "Response to a `tasks/cancel` request.\n\nPer spec, `CancelTaskResult = allOf[Result, Task]` — same shape as `GetTaskResult`.",
|
||||
|
|
@ -2813,18 +2811,12 @@
|
|||
{
|
||||
"$ref": "#/definitions/ReadResourceResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CallToolResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/ListToolsResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CreateElicitationResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/EmptyObject"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CreateTaskResult"
|
||||
},
|
||||
|
|
@ -2838,10 +2830,16 @@
|
|||
"$ref": "#/definitions/CancelTaskResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CustomResult"
|
||||
"$ref": "#/definitions/CallToolResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/GetTaskPayloadResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/EmptyObject"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CustomResult"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@
|
|||
"content": {
|
||||
"description": "The content returned by the tool (text, images, etc.)",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/definitions/Annotated"
|
||||
}
|
||||
|
|
@ -402,10 +403,7 @@
|
|||
"structuredContent": {
|
||||
"description": "An optional JSON object that represents the structured result of the tool call"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"content"
|
||||
]
|
||||
}
|
||||
},
|
||||
"CancelTaskResult": {
|
||||
"description": "Response to a `tasks/cancel` request.\n\nPer spec, `CancelTaskResult = allOf[Result, Task]` — same shape as `GetTaskResult`.",
|
||||
|
|
@ -2813,18 +2811,12 @@
|
|||
{
|
||||
"$ref": "#/definitions/ReadResourceResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CallToolResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/ListToolsResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CreateElicitationResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/EmptyObject"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CreateTaskResult"
|
||||
},
|
||||
|
|
@ -2838,10 +2830,16 @@
|
|||
"$ref": "#/definitions/CancelTaskResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CustomResult"
|
||||
"$ref": "#/definitions/CallToolResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/GetTaskPayloadResult"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/EmptyObject"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/CustomResult"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -298,18 +298,20 @@ async fn test_empty_content_array_with_is_error() {
|
|||
assert_eq!(result.is_error, Some(false));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_missing_content_is_rejected() {
|
||||
#[test]
|
||||
fn test_missing_content_defaults_to_empty() {
|
||||
let raw = json!({ "isError": false });
|
||||
let result: Result<CallToolResult, _> = serde_json::from_value(raw);
|
||||
assert!(result.is_err());
|
||||
let result: CallToolResult = serde_json::from_value(raw).unwrap();
|
||||
assert!(result.content.is_empty());
|
||||
assert_eq!(result.is_error, Some(false));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_missing_content_with_structured_content_is_rejected() {
|
||||
#[test]
|
||||
fn test_missing_content_with_structured_content_deserializes() {
|
||||
let raw = json!({ "structuredContent": {"key": "value"}, "isError": false });
|
||||
let result: Result<CallToolResult, _> = serde_json::from_value(raw);
|
||||
assert!(result.is_err());
|
||||
let result: CallToolResult = serde_json::from_value(raw).unwrap();
|
||||
assert!(result.content.is_empty());
|
||||
assert_eq!(result.structured_content.unwrap()["key"], "value");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -333,3 +335,13 @@ async fn test_empty_content_roundtrip() {
|
|||
let deserialized: CallToolResult = serde_json::from_value(v).unwrap();
|
||||
assert_eq!(deserialized, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call_tool_result_deserialize_without_content() {
|
||||
let json = json!({
|
||||
"structuredContent": {"message": "Hello"}
|
||||
});
|
||||
let result: CallToolResult = serde_json::from_value(json).unwrap();
|
||||
assert!(result.content.is_empty());
|
||||
assert!(result.structured_content.is_some());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue