Update to rmcp 1.1.0 (#7619)

Co-authored-by: Alex Hancock <alexhancock@block.xyz>
This commit is contained in:
Jack Amadeo
2026-03-05 21:40:52 -05:00
committed by GitHub
parent abadb87892
commit 325bf396af
61 changed files with 729 additions and 1757 deletions
@@ -325,12 +325,8 @@ pub fn response_to_message(response: &Value) -> Result<Message> {
.get(INPUT_FIELD)
.ok_or_else(|| anyhow!("Missing tool_use input"))?;
let tool_call = CallToolRequestParams {
meta: None,
task: None,
name: name.into(),
arguments: Some(object(input.clone())),
};
let tool_call =
CallToolRequestParams::new(name).with_arguments(object(input.clone()));
message = message.with_tool_request(id, Ok(tool_call));
}
Some(THINKING_TYPE) => {
@@ -692,11 +688,7 @@ where
}
};
let tool_call = CallToolRequestParams{
meta: None, task: None,
name: name.into(),
arguments: Some(object(parsed_args))
};
let tool_call = CallToolRequestParams::new(name).with_arguments(object(parsed_args));
let mut message = Message::new(
rmcp::model::Role::Assistant,
@@ -1126,12 +1118,8 @@ mod tests {
let messages = vec![
Message::assistant().with_tool_request(
"tool_1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "calculator".into(),
arguments: Some(object!({"expression": "2 + 2"})),
}),
Ok(CallToolRequestParams::new("calculator")
.with_arguments(object!({"expression": "2 + 2"}))),
),
Message::user().with_tool_response(
"tool_1",
@@ -1168,22 +1156,10 @@ mod tests {
Message::user().with_text("Hello"),
Message::assistant().with_text("").with_tool_request(
"tool_1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "search".into(),
arguments: Some(object!({"query": "test"})),
}),
),
Message::user().with_tool_response(
"tool_1",
Ok(rmcp::model::CallToolResult {
content: vec![],
structured_content: None,
is_error: Some(false),
meta: None,
}),
Ok(CallToolRequestParams::new("search").with_arguments(object!({"query": "test"}))),
),
Message::user()
.with_tool_response("tool_1", Ok(rmcp::model::CallToolResult::success(vec![]))),
];
let spec = format_messages(&messages);
+12 -36
View File
@@ -312,12 +312,8 @@ pub fn from_bedrock_content_block(block: &bedrock::ContentBlock) -> Result<Messa
bedrock::ContentBlock::Text(text) => MessageContent::text(text),
bedrock::ContentBlock::ToolUse(tool_use) => MessageContent::tool_request(
tool_use.tool_use_id.to_string(),
Ok(CallToolRequestParams {
meta: None,
task: None,
name: tool_use.name.clone().into(),
arguments: Some(object(from_bedrock_json(&tool_use.input.clone())?)),
}),
Ok(CallToolRequestParams::new(tool_use.name.clone())
.with_arguments(object(from_bedrock_json(&tool_use.input.clone())?))),
),
bedrock::ContentBlock::ToolResult(tool_res) => MessageContent::tool_response(
tool_res.tool_use_id.to_string(),
@@ -333,12 +329,7 @@ pub fn from_bedrock_content_block(block: &bedrock::ContentBlock) -> Result<Messa
.iter()
.map(from_bedrock_tool_result_content_block)
.collect::<ToolResult<Vec<_>>>()
.map(|content| rmcp::model::CallToolResult {
content,
structured_content: None,
is_error: Some(false),
meta: None,
})
.map(rmcp::model::CallToolResult::success)
},
),
bedrock::ContentBlock::CachePoint(_) => {
@@ -612,12 +603,8 @@ mod tests {
MessageContent::text("I'll use a tool"),
MessageContent::tool_request(
"tool_1".to_string(),
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: Some(object(json!({"param": "value"}))),
}),
Ok(CallToolRequestParams::new("test_tool")
.with_arguments(object(json!({"param": "value"})))),
),
],
);
@@ -652,12 +639,9 @@ mod tests {
Utc::now().timestamp(),
vec![MessageContent::tool_response(
"tool_1".to_string(),
Ok(CallToolResult {
content: vec![Content::text("Tool result text".to_string())],
structured_content: None,
is_error: Some(false),
meta: None,
}),
Ok(CallToolResult::success(vec![Content::text(
"Tool result text".to_string(),
)])),
)],
);
@@ -690,21 +674,13 @@ mod tests {
MessageContent::text("Using tools"),
MessageContent::tool_request(
"tool_1".to_string(),
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "tool_a".into(),
arguments: Some(object(json!({"key": "val"}))),
}),
Ok(CallToolRequestParams::new("tool_a")
.with_arguments(object(json!({"key": "val"})))),
),
MessageContent::tool_request(
"tool_2".to_string(),
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "tool_b".into(),
arguments: Some(object(json!({"key": "val"}))),
}),
Ok(CallToolRequestParams::new("tool_b")
.with_arguments(object(json!({"key": "val"})))),
),
],
);
@@ -366,12 +366,8 @@ pub fn response_to_message(response: &Value) -> anyhow::Result<Message> {
Ok(params) => {
content.push(MessageContent::tool_request(
id,
Ok(CallToolRequestParams {
meta: None,
task: None,
name: function_name.into(),
arguments: Some(object(params)),
}),
Ok(CallToolRequestParams::new(function_name)
.with_arguments(object(params))),
));
}
Err(e) => {
@@ -755,12 +751,8 @@ mod tests {
Message::user().with_text("How are you?"),
Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "example".into(),
arguments: Some(object!({"param1": "value1"})),
}),
Ok(CallToolRequestParams::new("example")
.with_arguments(object!({"param1": "value1"}))),
),
];
@@ -772,12 +764,7 @@ mod tests {
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
Ok(CallToolResult::success(vec![Content::text("Result")])),
));
let as_value =
@@ -802,12 +789,7 @@ mod tests {
fn test_format_messages_multiple_content() -> anyhow::Result<()> {
let mut messages = vec![Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "example".into(),
arguments: Some(object!({"param1": "value1"})),
}),
Ok(CallToolRequestParams::new("example").with_arguments(object!({"param1": "value1"}))),
)];
let tool_id = if let MessageContent::ToolRequest(request) = &messages[0].content[0] {
@@ -818,12 +800,7 @@ mod tests {
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
Ok(CallToolResult::success(vec![Content::text("Result")])),
));
let as_value =
@@ -1182,15 +1159,8 @@ mod tests {
#[test]
fn test_format_messages_tool_request_with_none_arguments() -> anyhow::Result<()> {
// Test that tool calls with None arguments are formatted as "{}" string
let message = Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: None, // This is the key case the fix addresses
}),
);
let message = Message::assistant()
.with_tool_request("tool1", Ok(CallToolRequestParams::new("test_tool")));
let spec = format_messages(&[message], &ImageFormat::OpenAi);
let as_value = serde_json::to_value(spec)?;
@@ -1215,12 +1185,8 @@ mod tests {
// Test that tool calls with Some arguments are properly JSON-serialized
let message = Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: Some(object!({"param": "value", "number": 42})),
}),
Ok(CallToolRequestParams::new("test_tool")
.with_arguments(object!({"param": "value", "number": 42}))),
);
let spec = format_messages(&[message], &ImageFormat::OpenAi);
@@ -1397,12 +1363,7 @@ mod tests {
let message = Message::assistant().with_tool_request_with_metadata(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: Some(object!({"param": "value"})),
}),
Ok(CallToolRequestParams::new("test_tool").with_arguments(object!({"param": "value"}))),
Some(&metadata),
None,
);
@@ -1534,12 +1495,7 @@ mod tests {
let message = Message::assistant().with_tool_request_with_metadata(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: None,
}),
Ok(CallToolRequestParams::new("test_tool")),
Some(&metadata),
None,
);
+10 -29
View File
@@ -292,11 +292,12 @@ fn process_response_part_impl(
Some(MessageContent::tool_request_with_metadata(
id,
Ok(CallToolRequestParams {
meta: None,
task: None,
name: name.to_string().into(),
arguments,
Ok({
let mut params = CallToolRequestParams::new(name.to_string());
if let Some(args) = arguments {
params = params.with_arguments(args);
}
params
}),
metadata.as_ref(),
))
@@ -640,12 +641,7 @@ mod tests {
0,
vec![MessageContent::tool_response(
id.to_string(),
Ok(CallToolResult {
content: tool_response,
structured_content: None,
is_error: Some(false),
meta: None,
}),
Ok(CallToolResult::success(tool_response)),
)],
)
}
@@ -719,21 +715,11 @@ mod tests {
let messages = vec![
set_up_tool_request_message(
"id",
CallToolRequestParams {
meta: None,
task: None,
name: "tool_name".into(),
arguments: Some(object(arguments.clone())),
},
CallToolRequestParams::new("tool_name").with_arguments(object(arguments.clone())),
),
set_up_action_required_message(
"id2",
CallToolRequestParams {
meta: None,
task: None,
name: "tool_name_2".into(),
arguments: Some(object(arguments.clone())),
},
CallToolRequestParams::new("tool_name_2").with_arguments(object(arguments.clone())),
),
];
let payload = format_messages(&messages);
@@ -970,12 +956,7 @@ mod tests {
}
fn tool_result(text: &str) -> CallToolResult {
CallToolResult {
content: vec![Content::text(text)],
structured_content: None,
is_error: Some(false),
meta: None,
}
CallToolResult::success(vec![Content::text(text)])
}
#[test]
+2 -6
View File
@@ -58,12 +58,8 @@ pub fn parse_xml_tool_calls(content: &str) -> (Option<String>, Vec<MessageConten
if is_valid_function_name(&function_name) {
tool_calls.push(MessageContent::tool_request(
id,
Ok(CallToolRequestParams {
meta: None,
task: None,
name: function_name.into(),
arguments: Some(object(serde_json::Value::Object(arguments))),
}),
Ok(CallToolRequestParams::new(function_name)
.with_arguments(object(serde_json::Value::Object(arguments)))),
));
} else {
let error = ErrorData {
+17 -69
View File
@@ -409,12 +409,8 @@ pub fn response_to_message(response: &Value) -> anyhow::Result<Message> {
Ok(params) => {
content.push(MessageContent::tool_request_with_metadata(
id,
Ok(CallToolRequestParams {
meta: None,
task: None,
name: function_name.into(),
arguments: Some(object(params)),
}),
Ok(CallToolRequestParams::new(function_name)
.with_arguments(object(params))),
metadata.as_ref(),
));
}
@@ -670,12 +666,7 @@ where
Ok(params) => {
MessageContent::tool_request_with_metadata(
id.clone(),
Ok(CallToolRequestParams {
meta: None,
task: None,
name: function_name.clone().into(),
arguments: Some(object(params)),
}),
Ok(CallToolRequestParams::new(function_name.clone()).with_arguments(object(params))),
metadata,
)
},
@@ -984,12 +975,8 @@ mod tests {
Message::user().with_text("How are you?"),
Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "example".into(),
arguments: Some(object!({"param1": "value1"})),
}),
Ok(CallToolRequestParams::new("example")
.with_arguments(object!({"param1": "value1"}))),
),
];
@@ -1002,12 +989,7 @@ mod tests {
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
Ok(CallToolResult::success(vec![Content::text("Result")])),
));
let spec = format_messages(&messages, &ImageFormat::OpenAi);
@@ -1030,12 +1012,7 @@ mod tests {
fn test_format_messages_multiple_content() -> anyhow::Result<()> {
let mut messages = vec![Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "example".into(),
arguments: Some(object!({"param1": "value1"})),
}),
Ok(CallToolRequestParams::new("example").with_arguments(object!({"param1": "value1"}))),
)];
// Get the ID from the tool request to use in the response
@@ -1047,12 +1024,7 @@ mod tests {
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
Ok(CallToolResult::success(vec![Content::text("Result")])),
));
let spec = format_messages(&messages, &ImageFormat::OpenAi);
@@ -1340,15 +1312,8 @@ mod tests {
#[test]
fn test_format_messages_tool_request_with_none_arguments() -> anyhow::Result<()> {
// Test that tool calls with None arguments are formatted as "{}" string
let message = Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: None, // This is the key case the fix addresses
}),
);
let message = Message::assistant()
.with_tool_request("tool1", Ok(CallToolRequestParams::new("test_tool")));
let spec = format_messages(&[message], &ImageFormat::OpenAi);
@@ -1371,12 +1336,8 @@ mod tests {
// Test that tool calls with Some arguments are properly JSON-serialized
let message = Message::assistant().with_tool_request(
"tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: Some(object!({"param": "value", "number": 42})),
}),
Ok(CallToolRequestParams::new("test_tool")
.with_arguments(object!({"param": "value", "number": 42}))),
);
let spec = format_messages(&[message], &ImageFormat::OpenAi);
@@ -1403,12 +1364,7 @@ mod tests {
// Test that FrontendToolRequest with None arguments are formatted as "{}" string
let message = Message::assistant().with_frontend_tool_request(
"frontend_tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "frontend_test_tool".into(),
arguments: None, // This is the key case the fix addresses
}),
Ok(CallToolRequestParams::new("frontend_test_tool")),
);
let spec = format_messages(&[message], &ImageFormat::OpenAi);
@@ -1432,12 +1388,8 @@ mod tests {
// Test that FrontendToolRequest with Some arguments are properly JSON-serialized
let message = Message::assistant().with_frontend_tool_request(
"frontend_tool1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "frontend_test_tool".into(),
arguments: Some(object!({"action": "click", "element": "button"})),
}),
Ok(CallToolRequestParams::new("frontend_test_tool")
.with_arguments(object!({"action": "click", "element": "button"}))),
);
let spec = format_messages(&[message], &ImageFormat::OpenAi);
@@ -1925,12 +1877,8 @@ data: [DONE]"#;
// Add a tool call to test that reasoning_content works with tool calls
message = message.with_tool_request(
"tool1",
Ok(rmcp::model::CallToolRequestParams {
meta: None,
task: None,
name: "test_tool".into(),
arguments: Some(rmcp::object!({"param": "value"})),
}),
Ok(rmcp::model::CallToolRequestParams::new("test_tool")
.with_arguments(rmcp::object!({"param": "value"}))),
);
let spec = format_messages(&[message], &ImageFormat::OpenAi);
@@ -473,12 +473,8 @@ pub fn responses_api_to_message(response: &ResponsesApiResponse) -> anyhow::Resu
ResponseContentBlock::ToolCall { id, name, input } => {
content.push(MessageContent::tool_request(
id.clone(),
Ok(CallToolRequestParams {
meta: None,
task: None,
name: name.clone().into(),
arguments: Some(object(input.clone())),
}),
Ok(CallToolRequestParams::new(name.clone())
.with_arguments(object(input.clone()))),
));
}
}
@@ -499,12 +495,8 @@ pub fn responses_api_to_message(response: &ResponsesApiResponse) -> anyhow::Resu
content.push(MessageContent::tool_request(
id.clone(),
Ok(CallToolRequestParams {
meta: None,
task: None,
name: name.clone().into(),
arguments: Some(object(parsed_args)),
}),
Ok(CallToolRequestParams::new(name.clone())
.with_arguments(object(parsed_args))),
));
}
}
@@ -559,12 +551,8 @@ fn process_streaming_output_items(
content.push(MessageContent::tool_request(
id,
Ok(CallToolRequestParams {
meta: None,
task: None,
name: name.into(),
arguments: Some(object(parsed_args)),
}),
Ok(CallToolRequestParams::new(name)
.with_arguments(object(parsed_args))),
));
}
}
@@ -584,12 +572,7 @@ fn process_streaming_output_items(
content.push(MessageContent::tool_request(
call_id,
Ok(CallToolRequestParams {
meta: None,
task: None,
name: name.into(),
arguments: Some(object(parsed_args)),
}),
Ok(CallToolRequestParams::new(name).with_arguments(object(parsed_args))),
));
}
}
@@ -835,23 +818,15 @@ mod tests {
.with_text("I'll create that file.")
.with_tool_request(
"call_1",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "shell".into(),
arguments: Some(object!({"command": "echo hello"})),
}),
Ok(CallToolRequestParams::new("shell")
.with_arguments(object!({"command": "echo hello"}))),
),
Message::assistant()
.with_text("Now let me verify.")
.with_tool_request(
"call_2",
Ok(CallToolRequestParams {
meta: None,
task: None,
name: "shell".into(),
arguments: Some(object!({"command": "cat file.txt"})),
}),
Ok(CallToolRequestParams::new("shell")
.with_arguments(object!({"command": "cat file.txt"}))),
),
];
@@ -187,21 +187,11 @@ pub fn parse_streaming_response(sse_data: &str) -> Result<Message> {
if !tool_input.is_empty() {
let input_value = serde_json::from_str::<Value>(&tool_input)
.unwrap_or_else(|_| Value::String(tool_input.clone()));
let tool_call = CallToolRequestParams {
meta: None,
task: None,
name: name.into(),
arguments: Some(object(input_value)),
};
let tool_call = CallToolRequestParams::new(name).with_arguments(object(input_value));
message = message.with_tool_request(&id, Ok(tool_call));
} else {
// Tool with no input - use empty object
let tool_call = CallToolRequestParams {
meta: None,
task: None,
name: name.into(),
arguments: Some(object!({})),
};
let tool_call = CallToolRequestParams::new(name).with_arguments(object!({}));
message = message.with_tool_request(&id, Ok(tool_call));
}
}
@@ -258,12 +248,7 @@ pub fn response_to_message(response: &Value) -> Result<Message> {
.ok_or_else(|| anyhow!("Missing tool input"))?
.clone();
let tool_call = CallToolRequestParams {
meta: None,
task: None,
name: name.into(),
arguments: Some(object(input)),
};
let tool_call = CallToolRequestParams::new(name).with_arguments(object(input));
message = message.with_tool_request(id, Ok(tool_call));
}
Some("thinking") => {
@@ -700,12 +685,8 @@ data: {"id":"a9537c2c-2017-4906-9817-2456168d89fa","model":"claude-sonnet-4-2025
use crate::conversation::message::Message;
// Create a conversation with text, tool requests, and tool responses
let tool_call = CallToolRequestParams {
meta: None,
task: None,
name: "calculator".into(),
arguments: Some(object!({"expression": "2 + 2"})),
};
let tool_call = CallToolRequestParams::new("calculator")
.with_arguments(object!({"expression": "2 + 2"}));
let messages = vec![
Message::user().with_text("Calculate 2 + 2"),