Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 0 additions & 93 deletions agent-client-protocol-schema/src/v1/elicitation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2094,78 +2094,6 @@ impl CompleteElicitationNotification {
}
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Data payload for the `UrlElicitationRequired` error, describing the URL elicitations
/// the user must complete.
#[serde_as]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct UrlElicitationRequiredData {
/// The URL elicitations the user must complete.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub elicitations: Vec<UrlElicitationRequiredItem>,
}

impl UrlElicitationRequiredData {
/// Builds [`UrlElicitationRequiredData`] with the required fields set; optional fields start unset or empty.
#[must_use]
pub fn new(elicitations: Vec<UrlElicitationRequiredItem>) -> Self {
Self { elicitations }
}
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// A single URL elicitation item within the `UrlElicitationRequired` error data.
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct UrlElicitationRequiredItem {
/// The elicitation mode (always `"url"` for this item type).
pub mode: ElicitationUrlOnlyMode,
/// The unique identifier for this elicitation.
pub elicitation_id: ElicitationId,
/// The URL the user should be directed to.
#[schemars(extend("format" = "uri"))]
pub url: String,
/// A human-readable message describing what input is needed.
pub message: String,
}

/// Type discriminator for URL-only elicitation error items.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ElicitationUrlOnlyMode {
/// URL elicitation mode.
#[default]
Url,
}

impl UrlElicitationRequiredItem {
/// Builds [`UrlElicitationRequiredItem`] with the required fields set; optional fields start unset or empty.
#[must_use]
pub fn new(
elicitation_id: impl Into<ElicitationId>,
url: impl Into<String>,
message: impl Into<String>,
) -> Self {
Self {
mode: ElicitationUrlOnlyMode::Url,
elicitation_id: elicitation_id.into(),
url: url.into(),
message: message.into(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -2524,27 +2452,6 @@ mod tests {
assert!(roundtripped.url.is_some());
}

#[test]
fn url_elicitation_required_data_serialization() {
let data = UrlElicitationRequiredData::new(vec![UrlElicitationRequiredItem::new(
"elic_1",
"https://example.com/auth",
"Please authenticate",
)]);

let json = serde_json::to_value(&data).unwrap();
assert_eq!(json["elicitations"][0]["mode"], "url");
assert_eq!(json["elicitations"][0]["elicitationId"], "elic_1");
assert_eq!(json["elicitations"][0]["url"], "https://example.com/auth");

let roundtripped: UrlElicitationRequiredData = serde_json::from_value(json).unwrap();
assert_eq!(roundtripped.elicitations.len(), 1);
assert_eq!(
roundtripped.elicitations[0].mode,
ElicitationUrlOnlyMode::Url
);
}

#[test]
fn schema_default_sets_object_type() {
let schema = ElicitationSchema::default();
Expand Down
27 changes: 0 additions & 27 deletions agent-client-protocol-schema/src/v1/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,6 @@ impl Error {
ErrorCode::AuthRequired.into()
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// The agent requires user input via a URL-based elicitation before it can proceed.
#[cfg(feature = "unstable_elicitation")]
#[must_use]
pub fn url_elicitation_required() -> Self {
ErrorCode::UrlElicitationRequired.into()
}

/// A given resource, such as a file, was not found.
#[must_use]
pub fn resource_not_found(uri: Option<String>) -> Self {
Expand Down Expand Up @@ -193,16 +182,6 @@ pub enum ErrorCode {
#[schemars(transform = error_code_transform)]
#[strum(to_string = "Resource not found")]
ResourceNotFound, // -32002
#[cfg(feature = "unstable_elicitation")]
/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// The agent requires user input via a URL-based elicitation before it can proceed.
#[schemars(transform = error_code_transform)]
#[strum(to_string = "URL elicitation required")]
UrlElicitationRequired, // -32042

/// Other undefined error code.
#[schemars(untagged)]
#[strum(to_string = "Unknown error")]
Expand All @@ -220,8 +199,6 @@ impl From<i32> for ErrorCode {
-32800 => ErrorCode::RequestCancelled,
-32000 => ErrorCode::AuthRequired,
-32002 => ErrorCode::ResourceNotFound,
#[cfg(feature = "unstable_elicitation")]
-32042 => ErrorCode::UrlElicitationRequired,
_ => ErrorCode::Other(value),
}
}
Expand All @@ -238,8 +215,6 @@ impl From<ErrorCode> for i32 {
ErrorCode::RequestCancelled => -32800,
ErrorCode::AuthRequired => -32000,
ErrorCode::ResourceNotFound => -32002,
#[cfg(feature = "unstable_elicitation")]
ErrorCode::UrlElicitationRequired => -32042,
ErrorCode::Other(value) => value,
}
}
Expand All @@ -266,8 +241,6 @@ fn error_code_transform(schema: &mut Schema) {
"RequestCancelled" => ErrorCode::RequestCancelled,
"AuthRequired" => ErrorCode::AuthRequired,
"ResourceNotFound" => ErrorCode::ResourceNotFound,
#[cfg(feature = "unstable_elicitation")]
"UrlElicitationRequired" => ErrorCode::UrlElicitationRequired,
_ => panic!("Unexpected error code name {name}"),
};
let mut description = schema
Expand Down
86 changes: 0 additions & 86 deletions agent-client-protocol-schema/src/v2/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8607,92 +8607,6 @@ impl IntoV2 for crate::v1::CompleteElicitationNotification {
}
}

#[cfg(feature = "unstable_elicitation")]
impl IntoV1 for super::UrlElicitationRequiredData {
type Output = crate::v1::UrlElicitationRequiredData;

fn into_v1(self) -> Result<Self::Output> {
let Self { elicitations } = self;
Ok(crate::v1::UrlElicitationRequiredData {
elicitations: elicitations.into_v1()?,
})
}
}

#[cfg(feature = "unstable_elicitation")]
impl IntoV2 for crate::v1::UrlElicitationRequiredData {
type Output = super::UrlElicitationRequiredData;

fn into_v2(self) -> Result<Self::Output> {
let Self { elicitations } = self;
Ok(super::UrlElicitationRequiredData {
elicitations: elicitations.into_v2()?,
})
}
}

#[cfg(feature = "unstable_elicitation")]
impl IntoV1 for super::UrlElicitationRequiredItem {
type Output = crate::v1::UrlElicitationRequiredItem;

fn into_v1(self) -> Result<Self::Output> {
let Self {
mode,
elicitation_id,
url,
message,
} = self;
Ok(crate::v1::UrlElicitationRequiredItem {
mode: mode.into_v1()?,
elicitation_id: elicitation_id.into_v1()?,
url: url.into_v1()?,
message: message.into_v1()?,
})
}
}

#[cfg(feature = "unstable_elicitation")]
impl IntoV2 for crate::v1::UrlElicitationRequiredItem {
type Output = super::UrlElicitationRequiredItem;

fn into_v2(self) -> Result<Self::Output> {
let Self {
mode,
elicitation_id,
url,
message,
} = self;
Ok(super::UrlElicitationRequiredItem {
mode: mode.into_v2()?,
elicitation_id: elicitation_id.into_v2()?,
url: url.into_v2()?,
message: message.into_v2()?,
})
}
}

#[cfg(feature = "unstable_elicitation")]
impl IntoV1 for super::ElicitationUrlOnlyMode {
type Output = crate::v1::ElicitationUrlOnlyMode;

fn into_v1(self) -> Result<Self::Output> {
Ok(match self {
Self::Url => crate::v1::ElicitationUrlOnlyMode::Url,
})
}
}

#[cfg(feature = "unstable_elicitation")]
impl IntoV2 for crate::v1::ElicitationUrlOnlyMode {
type Output = super::ElicitationUrlOnlyMode;

fn into_v2(self) -> Result<Self::Output> {
Ok(match self {
Self::Url => super::ElicitationUrlOnlyMode::Url,
})
}
}

impl IntoV1 for super::ContentBlock {
type Output = crate::v1::ContentBlock;

Expand Down
93 changes: 0 additions & 93 deletions agent-client-protocol-schema/src/v2/elicitation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2035,78 +2035,6 @@ impl CompleteElicitationNotification {
}
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Data payload for the `UrlElicitationRequired` error, describing the URL elicitations
/// the user must complete.
#[serde_as]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct UrlElicitationRequiredData {
/// The URL elicitations the user must complete.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub elicitations: Vec<UrlElicitationRequiredItem>,
}

impl UrlElicitationRequiredData {
/// Builds [`UrlElicitationRequiredData`] with the required fields set; optional fields start unset or empty.
#[must_use]
pub fn new(elicitations: Vec<UrlElicitationRequiredItem>) -> Self {
Self { elicitations }
}
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// A single URL elicitation item within the `UrlElicitationRequired` error data.
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct UrlElicitationRequiredItem {
/// The elicitation mode (always `"url"` for this item type).
pub mode: ElicitationUrlOnlyMode,
/// The unique identifier for this elicitation.
pub elicitation_id: ElicitationId,
/// The URL the user should be directed to.
#[schemars(extend("format" = "uri"))]
pub url: String,
/// A human-readable message describing what input is needed.
pub message: String,
}

/// Type discriminator for URL-only elicitation error items.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ElicitationUrlOnlyMode {
/// URL elicitation mode.
#[default]
Url,
}

impl UrlElicitationRequiredItem {
/// Builds [`UrlElicitationRequiredItem`] with the required fields set; optional fields start unset or empty.
#[must_use]
pub fn new(
elicitation_id: impl Into<ElicitationId>,
url: impl Into<String>,
message: impl Into<String>,
) -> Self {
Self {
mode: ElicitationUrlOnlyMode::Url,
elicitation_id: elicitation_id.into(),
url: url.into(),
message: message.into(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -2462,27 +2390,6 @@ mod tests {
assert!(roundtripped.url.is_some());
}

#[test]
fn url_elicitation_required_data_serialization() {
let data = UrlElicitationRequiredData::new(vec![UrlElicitationRequiredItem::new(
"elic_1",
"https://example.com/auth",
"Please authenticate",
)]);

let json = serde_json::to_value(&data).unwrap();
assert_eq!(json["elicitations"][0]["mode"], "url");
assert_eq!(json["elicitations"][0]["elicitationId"], "elic_1");
assert_eq!(json["elicitations"][0]["url"], "https://example.com/auth");

let roundtripped: UrlElicitationRequiredData = serde_json::from_value(json).unwrap();
assert_eq!(roundtripped.elicitations.len(), 1);
assert_eq!(
roundtripped.elicitations[0].mode,
ElicitationUrlOnlyMode::Url
);
}

#[test]
fn schema_default_sets_object_type() {
let schema = ElicitationSchema::default();
Expand Down
Loading
Loading