fix: api ergonomics follow-up (#720)

* fix: builder with_* methods take T instead of Option<T>

* fix: emit conditional builder calls for optional fields in macros

* fix: convert with_task, with_stop_reason, with_logger, with_content to proper builders

* fix: update test callers for new builder signatures

* fix: simplify make_task helper and remove unused import

* fix: update sampling_stdio example for new with_stop_reason signature

* fix: make annotations and execution Option<Expr> consistent with other fields

* fix: remove unused none_expr import
This commit is contained in:
Dale Seo 2026-03-03 12:05:32 -05:00 • committed by GitHub
commit 2d90b76501
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 81 additions and 99 deletions

View file

@ -1455,13 +1455,10 @@ impl LoggingMessageNotificationParam {
}
}
/// Create with a logger name.
pub fn with_logger(level: LoggingLevel, logger: impl Into<String>, data: Value) -> Self {
Self {
level,
logger: Some(logger.into()),
data,
}
/// Set the logger name.
pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
self.logger = Some(logger.into());
self
}
}
@ -2605,12 +2602,10 @@ impl CreateElicitationResult {
}
}
/// Create with content.
pub fn with_content(action: ElicitationAction, content: Value) -> Self {
Self {
action,
content: Some(content),
}
/// Set the content on this result.
pub fn with_content(mut self, content: Value) -> Self {
self.content = Some(content);
self
}
}
@ -2822,8 +2817,8 @@ impl CallToolRequestParams {
}
/// Sets the task metadata for this tool call.
pub fn with_task(mut self, task: Option<JsonObject>) -> Self {
self.task = task;
pub fn with_task(mut self, task: JsonObject) -> Self {
self.task = Some(task);
self
}
}
@ -2889,8 +2884,8 @@ impl CreateMessageResult {
pub const STOP_REASON_TOOL_USE: &str = "toolUse";
/// Set the stop reason.
pub fn with_stop_reason(mut self, stop_reason: Option<String>) -> Self {
self.stop_reason = stop_reason;
pub fn with_stop_reason(mut self, stop_reason: impl Into<String>) -> Self {
self.stop_reason = Some(stop_reason.into());
self
}

View file

@ -68,20 +68,20 @@ impl Prompt {
}
/// Set the human-readable title
pub fn with_title(mut self, title: Option<String>) -> Self {
self.title = title;
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
/// Set the icons
pub fn with_icons(mut self, icons: Option<Vec<Icon>>) -> Self {
self.icons = icons;
pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
self.icons = Some(icons);
self
}
/// Set the metadata
pub fn with_meta(mut self, meta: Option<Meta>) -> Self {
self.meta = meta;
pub fn with_meta(mut self, meta: Meta) -> Self {
self.meta = Some(meta);
self
}
}

View file

@ -261,32 +261,32 @@ impl Tool {
}
/// Set the human-readable title
pub fn with_title(mut self, title: Option<String>) -> Self {
self.title = title;
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
/// Set the output schema from a raw value
pub fn with_raw_output_schema(mut self, output_schema: Option<Arc<JsonObject>>) -> Self {
self.output_schema = output_schema;
pub fn with_raw_output_schema(mut self, output_schema: Arc<JsonObject>) -> Self {
self.output_schema = Some(output_schema);
self
}
/// Set the annotations
pub fn with_annotations(mut self, annotations: Option<ToolAnnotations>) -> Self {
self.annotations = annotations;
pub fn with_annotations(mut self, annotations: ToolAnnotations) -> Self {
self.annotations = Some(annotations);
self
}
/// Set the icons
pub fn with_icons(mut self, icons: Option<Vec<Icon>>) -> Self {
self.icons = icons;
pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
self.icons = Some(icons);
self
}
/// Set the metadata
pub fn with_meta(mut self, meta: Option<Meta>) -> Self {
self.meta = meta;
pub fn with_meta(mut self, meta: Meta) -> Self {
self.meta = Some(meta);
self
}
@ -298,8 +298,8 @@ impl Tool {
}
/// Set the execution configuration for this tool.
pub fn with_execution(mut self, execution: Option<ToolExecution>) -> Self {
self.execution = execution;
pub fn with_execution(mut self, execution: ToolExecution) -> Self {
self.execution = Some(execution);
self
}

View file

@ -78,7 +78,7 @@ impl ClientHandler for TestClientHandler {
SamplingMessage::assistant_text(response.to_string()),
"test-model".to_string(),
)
.with_stop_reason(Some(CreateMessageResult::STOP_REASON_END_TURN.to_string())))
.with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN))
}
fn on_logging_message(

View file

@ -55,7 +55,7 @@ async fn test_sampling_result_structure() -> Result<()> {
SamplingMessage::assistant_text("The capital of France is Paris."),
"test-model".to_string(),
)
.with_stop_reason(Some(CreateMessageResult::STOP_REASON_END_TURN.to_string()));
.with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN);
let json = serde_json::to_string(&result)?;
let deserialized: CreateMessageResult = serde_json::from_str(&json)?;
@ -436,7 +436,7 @@ async fn test_create_message_result_tool_use_stop_reason() -> Result<()> {
),
"test-model".to_string(),
)
.with_stop_reason(Some(CreateMessageResult::STOP_REASON_TOOL_USE.to_string()));
.with_stop_reason(CreateMessageResult::STOP_REASON_TOOL_USE);
let json = serde_json::to_string(&result)?;
let deserialized: CreateMessageResult = serde_json::from_str(&json)?;
@ -688,7 +688,7 @@ async fn test_create_message_result_validate_rejects_user_role() {
SamplingMessage::user_text("This should not be a user message"),
"test-model".to_string(),
)
.with_stop_reason(Some(CreateMessageResult::STOP_REASON_END_TURN.to_string()));
.with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN);
let err = result.validate().unwrap_err();
assert!(
@ -703,7 +703,7 @@ async fn test_create_message_result_validate_accepts_assistant_role() {
SamplingMessage::assistant_text("Hello!"),
"test-model".to_string(),
)
.with_stop_reason(Some(CreateMessageResult::STOP_REASON_END_TURN.to_string()));
.with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN);
assert!(result.validate().is_ok());
}

View file

@ -13,7 +13,6 @@ use rmcp::{
model::{CallToolRequestParams, ClientInfo, ErrorCode, JsonObject},
tool, tool_handler, tool_router,
};
use serde_json::json;
/// Server with tools having different task support modes.
#[derive(Debug, Clone)]
@ -75,8 +74,8 @@ impl ClientHandler for DummyClientHandler {
}
/// Helper to create a task object for tool calls
fn make_task() -> Option<JsonObject> {
Some(json!({}).as_object().unwrap().clone())
fn make_task() -> JsonObject {
serde_json::Map::new()
}
#[tokio::test]