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
46 changes: 26 additions & 20 deletions agent-client-protocol-schema/src/v1/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1740,13 +1740,9 @@ impl CloseSessionResponse {
#[non_exhaustive]
pub struct ListSessionsRequest {
/// Filter sessions by working directory. Must be an absolute path.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub cwd: Option<PathBuf>,
/// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub cursor: Option<String>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
Expand Down Expand Up @@ -2899,8 +2895,6 @@ pub struct McpServerHttp {
/// URL to the MCP server.
pub url: String,
/// HTTP headers to set when making requests to the MCP server.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub headers: Vec<HttpHeader>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
Expand Down Expand Up @@ -2957,8 +2951,6 @@ pub struct McpServerSse {
/// URL to the MCP server.
pub url: String,
/// HTTP headers to set when making requests to the MCP server.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub headers: Vec<HttpHeader>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
Expand Down Expand Up @@ -3098,12 +3090,8 @@ pub struct McpServerStdio {
/// Absolute path to the MCP server executable.
pub command: PathBuf,
/// Command-line arguments to pass to the MCP server.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub args: Vec<String>,
/// Environment variables to set when launching the MCP server.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub env: Vec<EnvVariable>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
Expand Down Expand Up @@ -3277,8 +3265,6 @@ pub struct PromptRequest {
/// When available, [`ContentBlock::Resource`] is preferred
/// as it avoids extra round-trips and allows the message to include
/// pieces of context from sources the agent may not have access to.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub prompt: Vec<ContentBlock>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
Expand Down Expand Up @@ -3636,8 +3622,6 @@ pub struct ProviderInfo {
pub required: bool,
/// Current effective non-secret routing config.
/// Null or omitted means provider is disabled.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub current: Option<ProviderCurrentConfig>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
Expand Down Expand Up @@ -3742,8 +3726,6 @@ impl ListProvidersRequest {
#[non_exhaustive]
pub struct ListProvidersResponse {
/// Configurable providers with current routing info suitable for UI display.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub providers: Vec<ProviderInfo>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
Expand Down Expand Up @@ -3803,8 +3785,6 @@ pub struct SetProviderRequest {
pub base_url: String,
/// Full headers map for this provider.
/// May include authorization, routing, or other integration-specific headers.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub headers: HashMap<String, String>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
Expand Down Expand Up @@ -6661,4 +6641,30 @@ mod test_serialization {
let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
assert!(deserialized.providers.is_some());
}

#[test]
fn prompt_request_rejects_malformed_content_block() {
use serde_json::json;

assert!(
serde_json::from_value::<PromptRequest>(json!({
"sessionId": "sess-1",
"prompt": [{"type": "text"}]
}))
.is_err()
);
}

#[test]
fn prompt_request_rejects_non_array_prompt() {
use serde_json::json;

assert!(
serde_json::from_value::<PromptRequest>(json!({
"sessionId": "sess-1",
"prompt": "hello"
}))
.is_err()
);
}
}
24 changes: 22 additions & 2 deletions agent-client-protocol-schema/src/v1/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,8 +656,6 @@ pub struct RequestPermissionRequest {
/// Details about the tool call requiring permission.
pub tool_call: ToolCallUpdate,
/// Available permission options for the user to choose from.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
pub options: Vec<PermissionOption>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
Expand Down Expand Up @@ -2982,4 +2980,26 @@ mod tests {
.unwrap();
assert_eq!(request_with_null_params.params, None);
}

#[test]
fn request_permission_request_rejects_malformed_options() {
use serde_json::json;

assert!(
serde_json::from_value::<RequestPermissionRequest>(json!({
"sessionId": "sess-1",
"toolCall": {"toolCallId": "tc-1"},
"options": "not-an-array"
}))
.is_err()
);
assert!(
serde_json::from_value::<RequestPermissionRequest>(json!({
"sessionId": "sess-1",
"toolCall": {"toolCallId": "tc-1"},
"options": [{"optionId": "allow"}]
}))
.is_err()
);
}
}
74 changes: 17 additions & 57 deletions agent-client-protocol-schema/src/v1/elicitation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,23 +131,15 @@ pub struct StringPropertySchema {
#[serde(default)]
pub description: Option<String>,
/// Minimum string length.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub min_length: Option<u32>,
/// Maximum string length.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub max_length: Option<u32>,
/// Pattern the string must match.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub pattern: Option<String>,
/// String format.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub format: Option<StringFormat>,
/// Default value.
Expand All @@ -156,14 +148,10 @@ pub struct StringPropertySchema {
#[serde(default)]
pub default: Option<String>,
/// Enum values for untitled single-select enums.
#[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
#[serde(default)]
#[serde(rename = "enum")]
pub enum_values: Option<Vec<String>>,
/// Titled enum options for titled single-select enums.
#[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
#[serde(default)]
#[serde(rename = "oneOf")]
pub one_of: Option<Vec<EnumOption>>,
Expand Down Expand Up @@ -315,13 +303,9 @@ pub struct NumberPropertySchema {
#[serde(default)]
pub description: Option<String>,
/// Minimum value (inclusive).
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub minimum: Option<f64>,
/// Maximum value (inclusive).
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub maximum: Option<f64>,
/// Default value.
Expand Down Expand Up @@ -413,13 +397,9 @@ pub struct IntegerPropertySchema {
#[serde(default)]
pub description: Option<String>,
/// Minimum value (inclusive).
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub minimum: Option<i64>,
/// Maximum value (inclusive).
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub maximum: Option<i64>,
/// Default value.
Expand Down Expand Up @@ -574,8 +554,6 @@ impl BooleanPropertySchema {
#[non_exhaustive]
pub struct StringMultiSelectItems {
/// Allowed enum values.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
#[serde(rename = "enum")]
pub values: Vec<String>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
Expand Down Expand Up @@ -616,8 +594,6 @@ impl StringMultiSelectItems {
#[non_exhaustive]
pub struct TitledMultiSelectItems {
/// Titled enum options.
#[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
#[serde(rename = "anyOf")]
pub options: Vec<EnumOption>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
Expand Down Expand Up @@ -772,13 +748,9 @@ pub struct MultiSelectPropertySchema {
#[serde(default)]
pub description: Option<String>,
/// Minimum number of items to select.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub min_items: Option<u64>,
/// Maximum number of items to select.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub max_items: Option<u64>,
/// The items definition describing allowed values.
Expand Down Expand Up @@ -1054,13 +1026,9 @@ pub struct ElicitationSchema {
#[serde(default)]
pub title: Option<String>,
/// Property definitions (must be primitive types).
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub properties: BTreeMap<String, ElicitationPropertySchema>,
/// List of required property names.
#[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
#[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
#[serde(default)]
pub required: Option<Vec<String>>,
/// Optional description of what this schema represents.
Expand Down Expand Up @@ -1951,8 +1919,6 @@ impl From<OtherElicitationAction> for ElicitationAction {
#[non_exhaustive]
pub struct ElicitationAcceptAction {
/// The user-provided content, if any, as an object matching the requested schema.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub content: Option<BTreeMap<String, ElicitationContentValue>>,
}
Expand Down Expand Up @@ -2781,34 +2747,28 @@ mod tests {
}

#[test]
fn response_accept_defaults_non_object_content() {
let response = serde_json::from_value::<CreateElicitationResponse>(json!({
"action": "accept",
"content": "Alice"
}))
.unwrap();

assert_eq!(
response.action,
ElicitationAction::Accept(ElicitationAcceptAction::new())
fn response_accept_rejects_non_object_content() {
assert!(
serde_json::from_value::<CreateElicitationResponse>(json!({
"action": "accept",
"content": "Alice"
}))
.is_err()
);
}

#[test]
fn response_accept_defaults_nested_object_content() {
let response = serde_json::from_value::<CreateElicitationResponse>(json!({
"action": "accept",
"content": {
"profile": {
"name": "Alice"
fn response_accept_rejects_nested_object_content() {
assert!(
serde_json::from_value::<CreateElicitationResponse>(json!({
"action": "accept",
"content": {
"profile": {
"name": "Alice"
}
}
}
}))
.unwrap();

assert_eq!(
response.action,
ElicitationAction::Accept(ElicitationAcceptAction::new())
}))
.is_err()
);
}

Expand Down
2 changes: 0 additions & 2 deletions agent-client-protocol-schema/src/v1/mcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ pub struct MessageMcpRequest {
/// Optional inner MCP params.
///
/// If omitted or set to `null`, the inner MCP message has no params.
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub params: Option<serde_json::Map<String, serde_json::Value>>,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
Expand Down
Loading