feat!: add MRTR model types (SEP-2322) (#915)
* feat!: add SEP-2322 MRTR model types * feat!: remove URLElicitationRequiredError (SEP-2322)
This commit is contained in:
parent
519577601d
commit
f4ff56b81d
1 changed files with 969 additions and 255 deletions
|
|
@ -12,6 +12,7 @@ mod content;
|
|||
mod elicitation_schema;
|
||||
mod extension;
|
||||
mod meta;
|
||||
mod mrtr;
|
||||
mod prompt;
|
||||
mod resource;
|
||||
mod serde_impl;
|
||||
|
|
@ -23,6 +24,7 @@ pub use content::*;
|
|||
pub use elicitation_schema::*;
|
||||
pub use extension::*;
|
||||
pub use meta::*;
|
||||
pub use mrtr::*;
|
||||
pub use prompt::*;
|
||||
pub use resource::*;
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
|
|
@ -516,7 +518,6 @@ impl ErrorCode {
|
|||
pub const INVALID_PARAMS: Self = Self(-32602);
|
||||
pub const INTERNAL_ERROR: Self = Self(-32603);
|
||||
pub const PARSE_ERROR: Self = Self(-32700);
|
||||
pub const URL_ELICITATION_REQUIRED: Self = Self(-32042);
|
||||
}
|
||||
|
||||
/// Error information for JSON-RPC error responses.
|
||||
|
|
@ -572,12 +573,6 @@ impl ErrorData {
|
|||
pub fn internal_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
|
||||
Self::new(ErrorCode::INTERNAL_ERROR, message, data)
|
||||
}
|
||||
pub fn url_elicitation_required(
|
||||
message: impl Into<Cow<'static, str>>,
|
||||
data: Option<Value>,
|
||||
) -> Self {
|
||||
Self::new(ErrorCode::URL_ELICITATION_REQUIRED, message, data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents any JSON-RPC message that can be sent or received.
|
||||
|
|
@ -684,6 +679,71 @@ impl From<EmptyResult> for () {
|
|||
fn from(_value: EmptyResult) {}
|
||||
}
|
||||
|
||||
/// Indicates the type of a result object, allowing the client to
|
||||
/// determine how to parse the response.
|
||||
///
|
||||
/// The spec defines this as an open string (`"complete" | "input_required" | string`),
|
||||
/// so unknown values are preserved rather than rejected. Servers implementing this
|
||||
/// protocol version MUST include `resultType` in every result. For backward
|
||||
/// compatibility, clients MUST treat an absent field as `"complete"`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct ResultType(Cow<'static, str>);
|
||||
|
||||
impl ResultType {
|
||||
pub const COMPLETE: Self = Self(Cow::Borrowed("complete"));
|
||||
pub const INPUT_REQUIRED: Self = Self(Cow::Borrowed("input_required"));
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Returns `true` if this is `"input_required"`.
|
||||
pub fn is_input_required(&self) -> bool {
|
||||
self.0 == "input_required"
|
||||
}
|
||||
|
||||
/// Returns `true` if this is `"complete"`.
|
||||
pub fn is_complete(&self) -> bool {
|
||||
self.0 == "complete"
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ResultType {
|
||||
fn default() -> Self {
|
||||
Self::COMPLETE
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ResultType {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ResultType {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s: String = Deserialize::deserialize(deserializer)?;
|
||||
match s.as_str() {
|
||||
"complete" => Ok(Self::COMPLETE),
|
||||
"input_required" => Ok(Self::INPUT_REQUIRED),
|
||||
_ => Ok(Self(Cow::Owned(s))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ResultType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A catch-all response either side can use for custom requests.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[serde(transparent)]
|
||||
|
|
@ -1185,6 +1245,9 @@ macro_rules! paginated_result {
|
|||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
|
||||
pub struct $t {
|
||||
/// Result type discriminator. Absent values deserialize as `"complete"`.
|
||||
#[serde(default)]
|
||||
pub result_type: ResultType,
|
||||
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||
pub meta: Option<Meta>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -1197,6 +1260,7 @@ macro_rules! paginated_result {
|
|||
items: $t_item,
|
||||
) -> Self {
|
||||
Self {
|
||||
result_type: ResultType::default(),
|
||||
meta: None,
|
||||
next_cursor: None,
|
||||
$i_item: items,
|
||||
|
|
@ -1240,6 +1304,13 @@ pub struct ReadResourceRequestParams {
|
|||
pub meta: Option<Meta>,
|
||||
/// The URI of the resource to read
|
||||
pub uri: String,
|
||||
/// Client responses to server-initiated input requests from a previous
|
||||
/// [`InputRequiredResult`].
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub input_responses: Option<InputResponses>,
|
||||
/// Opaque request state echoed back from a previous [`InputRequiredResult`].
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub request_state: Option<String>,
|
||||
}
|
||||
|
||||
impl ReadResourceRequestParams {
|
||||
|
|
@ -1248,6 +1319,8 @@ impl ReadResourceRequestParams {
|
|||
Self {
|
||||
meta: None,
|
||||
uri: uri.into(),
|
||||
input_responses: None,
|
||||
request_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1256,6 +1329,18 @@ impl ReadResourceRequestParams {
|
|||
self.meta = Some(meta);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the input responses for an MRTR retry.
|
||||
pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
|
||||
self.input_responses = Some(input_responses);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the request state for an MRTR retry.
|
||||
pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
|
||||
self.request_state = Some(request_state.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestParamsMeta for ReadResourceRequestParams {
|
||||
|
|
@ -1276,6 +1361,9 @@ pub type ReadResourceRequestParam = ReadResourceRequestParams;
|
|||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[non_exhaustive]
|
||||
pub struct ReadResourceResult {
|
||||
/// Result type discriminator. Absent values deserialize as `"complete"`.
|
||||
#[serde(default)]
|
||||
pub result_type: ResultType,
|
||||
/// The actual content of the resource
|
||||
pub contents: Vec<ResourceContents>,
|
||||
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -1286,6 +1374,7 @@ impl ReadResourceResult {
|
|||
/// Create a new ReadResourceResult with the given contents.
|
||||
pub fn new(contents: Vec<ResourceContents>) -> Self {
|
||||
Self {
|
||||
result_type: ResultType::default(),
|
||||
contents,
|
||||
meta: None,
|
||||
}
|
||||
|
|
@ -1433,6 +1522,13 @@ pub struct GetPromptRequestParams {
|
|||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub arguments: Option<JsonObject>,
|
||||
/// Client responses to server-initiated input requests from a previous
|
||||
/// [`InputRequiredResult`].
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub input_responses: Option<InputResponses>,
|
||||
/// Opaque request state echoed back from a previous [`InputRequiredResult`].
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub request_state: Option<String>,
|
||||
}
|
||||
|
||||
impl GetPromptRequestParams {
|
||||
|
|
@ -1442,6 +1538,8 @@ impl GetPromptRequestParams {
|
|||
meta: None,
|
||||
name: name.into(),
|
||||
arguments: None,
|
||||
input_responses: None,
|
||||
request_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1456,6 +1554,18 @@ impl GetPromptRequestParams {
|
|||
self.meta = Some(meta);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the input responses for an MRTR retry.
|
||||
pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
|
||||
self.input_responses = Some(input_responses);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the request state for an MRTR retry.
|
||||
pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
|
||||
self.request_state = Some(request_state.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestParamsMeta for GetPromptRequestParams {
|
||||
|
|
@ -2438,6 +2548,9 @@ impl CompletionInfo {
|
|||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[non_exhaustive]
|
||||
pub struct CompleteResult {
|
||||
/// Result type discriminator. Absent values deserialize as `"complete"`.
|
||||
#[serde(default)]
|
||||
pub result_type: ResultType,
|
||||
pub completion: CompletionInfo,
|
||||
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||
pub meta: Option<Meta>,
|
||||
|
|
@ -2447,6 +2560,7 @@ impl CompleteResult {
|
|||
/// Create a new CompleteResult with the given completion info.
|
||||
pub fn new(completion: CompletionInfo) -> Self {
|
||||
Self {
|
||||
result_type: ResultType::default(),
|
||||
completion,
|
||||
meta: None,
|
||||
}
|
||||
|
|
@ -2653,7 +2767,6 @@ pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNoti
|
|||
// Elicitation allows servers to request interactive input from users during tool execution.
|
||||
const_string!(ElicitationCreateRequestMethod = "elicitation/create");
|
||||
const_string!(ElicitationResponseNotificationMethod = "notifications/elicitation/response");
|
||||
const_string!(ElicitationCompletionNotificationMethod = "notifications/elicitation/complete");
|
||||
|
||||
/// Represents the possible actions a user can take in response to an elicitation request.
|
||||
///
|
||||
|
|
@ -2888,34 +3001,6 @@ pub type ElicitRequest = Request<ElicitationCreateRequestMethod, ElicitRequestPa
|
|||
#[deprecated(since = "2.0.0", note = "Renamed to ElicitRequest")]
|
||||
pub type CreateElicitationRequest = ElicitRequest;
|
||||
|
||||
/// Notification parameters for an url elicitation completion notification.
|
||||
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[non_exhaustive]
|
||||
pub struct ElicitationResponseNotificationParam {
|
||||
pub elicitation_id: String,
|
||||
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||
pub meta: Option<Meta>,
|
||||
}
|
||||
|
||||
impl ElicitationResponseNotificationParam {
|
||||
/// Create a new ElicitationResponseNotificationParam.
|
||||
pub fn new(elicitation_id: impl Into<String>) -> Self {
|
||||
Self {
|
||||
elicitation_id: elicitation_id.into(),
|
||||
meta: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Notification sent when an url elicitation process is completed.
|
||||
pub type ElicitationCompleteNotification =
|
||||
Notification<ElicitationCompletionNotificationMethod, ElicitationResponseNotificationParam>;
|
||||
|
||||
#[deprecated(since = "2.0.0", note = "Renamed to ElicitationCompleteNotification")]
|
||||
pub type ElicitationCompletionNotification = ElicitationCompleteNotification;
|
||||
|
||||
// =============================================================================
|
||||
// TOOL EXECUTION RESULTS
|
||||
// =============================================================================
|
||||
|
|
@ -2929,6 +3014,9 @@ pub type ElicitationCompletionNotification = ElicitationCompleteNotification;
|
|||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[non_exhaustive]
|
||||
pub struct CallToolResult {
|
||||
/// Result type discriminator. Absent values deserialize as `"complete"`.
|
||||
#[serde(default)]
|
||||
pub result_type: ResultType,
|
||||
/// The content returned by the tool (text, images, etc.)
|
||||
#[serde(default)]
|
||||
pub content: Vec<ContentBlock>,
|
||||
|
|
@ -2956,6 +3044,8 @@ impl<'de> Deserialize<'de> for CallToolResult {
|
|||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Helper {
|
||||
#[serde(default)]
|
||||
result_type: ResultType,
|
||||
content: Option<Vec<ContentBlock>>,
|
||||
structured_content: Option<Value>,
|
||||
is_error: Option<bool>,
|
||||
|
|
@ -2977,6 +3067,7 @@ impl<'de> Deserialize<'de> for CallToolResult {
|
|||
}
|
||||
|
||||
Ok(CallToolResult {
|
||||
result_type: helper.result_type,
|
||||
content: helper.content.unwrap_or_default(),
|
||||
structured_content: helper.structured_content,
|
||||
is_error: helper.is_error,
|
||||
|
|
@ -2989,6 +3080,7 @@ impl CallToolResult {
|
|||
/// Create a successful tool result with unstructured content
|
||||
pub fn success(content: Vec<ContentBlock>) -> Self {
|
||||
CallToolResult {
|
||||
result_type: ResultType::default(),
|
||||
content,
|
||||
structured_content: None,
|
||||
is_error: Some(false),
|
||||
|
|
@ -3046,6 +3138,7 @@ impl CallToolResult {
|
|||
/// ```
|
||||
pub fn error(content: Vec<ContentBlock>) -> Self {
|
||||
CallToolResult {
|
||||
result_type: ResultType::default(),
|
||||
content,
|
||||
structured_content: None,
|
||||
is_error: Some(true),
|
||||
|
|
@ -3068,6 +3161,7 @@ impl CallToolResult {
|
|||
/// ```
|
||||
pub fn structured(value: Value) -> Self {
|
||||
CallToolResult {
|
||||
result_type: ResultType::default(),
|
||||
content: vec![ContentBlock::text(value.to_string())],
|
||||
structured_content: Some(value),
|
||||
is_error: Some(false),
|
||||
|
|
@ -3094,6 +3188,7 @@ impl CallToolResult {
|
|||
/// ```
|
||||
pub fn structured_error(value: Value) -> Self {
|
||||
CallToolResult {
|
||||
result_type: ResultType::default(),
|
||||
content: vec![ContentBlock::text(value.to_string())],
|
||||
structured_content: Some(value),
|
||||
is_error: Some(true),
|
||||
|
|
@ -3170,6 +3265,14 @@ pub struct CallToolRequestParams {
|
|||
/// Task metadata for async task management (SEP-1319)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub task: Option<TaskMetadata>,
|
||||
/// Client responses to server-initiated input requests from a previous
|
||||
/// [`InputRequiredResult`]. Present only when retrying after an incomplete result.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub input_responses: Option<InputResponses>,
|
||||
/// Opaque request state echoed back from a previous [`InputRequiredResult`].
|
||||
/// Clients MUST return this value exactly as received.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub request_state: Option<String>,
|
||||
}
|
||||
|
||||
impl CallToolRequestParams {
|
||||
|
|
@ -3180,6 +3283,8 @@ impl CallToolRequestParams {
|
|||
name: name.into(),
|
||||
arguments: None,
|
||||
task: None,
|
||||
input_responses: None,
|
||||
request_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3194,6 +3299,18 @@ impl CallToolRequestParams {
|
|||
self.task = Some(task);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the input responses for an MRTR retry.
|
||||
pub fn with_input_responses(mut self, input_responses: InputResponses) -> Self {
|
||||
self.input_responses = Some(input_responses);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the request state for an MRTR retry.
|
||||
pub fn with_request_state(mut self, request_state: impl Into<String>) -> Self {
|
||||
self.request_state = Some(request_state.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestParamsMeta for CallToolRequestParams {
|
||||
|
|
@ -3286,6 +3403,9 @@ impl CreateMessageResult {
|
|||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[non_exhaustive]
|
||||
pub struct GetPromptResult {
|
||||
/// Result type discriminator. Absent values deserialize as `"complete"`.
|
||||
#[serde(default)]
|
||||
pub result_type: ResultType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
pub messages: Vec<PromptMessage>,
|
||||
|
|
@ -3297,6 +3417,7 @@ impl GetPromptResult {
|
|||
/// Create a new GetPromptResult with required fields.
|
||||
pub fn new(messages: Vec<PromptMessage>) -> Self {
|
||||
Self {
|
||||
result_type: ResultType::default(),
|
||||
description: None,
|
||||
messages,
|
||||
meta: None,
|
||||
|
|
@ -3662,7 +3783,6 @@ ts_union!(
|
|||
| ResourceListChangedNotification
|
||||
| ToolListChangedNotification
|
||||
| PromptListChangedNotification
|
||||
| ElicitationCompleteNotification
|
||||
| TaskStatusNotification
|
||||
| CustomNotification;
|
||||
);
|
||||
|
|
@ -3683,6 +3803,7 @@ ts_union!(
|
|||
| GetTaskResult
|
||||
| CancelTaskResult
|
||||
| CallToolResult
|
||||
| InputRequiredResult
|
||||
| GetTaskPayloadResult
|
||||
| EmptyResult
|
||||
| CustomResult
|
||||
|
|
|
|||
Loading…
Reference in a new issue