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
4 changes: 2 additions & 2 deletions agent-client-protocol-schema/src/v1/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2513,11 +2513,11 @@ pub enum ClientResponse {
/// Successful result returned for a `mcp/disconnect` request.
#[cfg(feature = "unstable_mcp_over_acp")]
DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
/// Successful result returned by an extension method outside the core ACP method set.
ExtMethodResponse(ExtResponse),
/// Successful result returned by an MCP-over-ACP `mcp/message` request.
#[cfg(feature = "unstable_mcp_over_acp")]
MessageMcpResponse(MessageMcpResponse),
/// Successful result returned by an extension method outside the core ACP method set.
ExtMethodResponse(ExtResponse),
}

/// All possible notifications that an agent can send to a client.
Expand Down
25 changes: 12 additions & 13 deletions agent-client-protocol-schema/src/v2/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionNotification {
pub struct UpdateSessionNotification {
/// The ID of the session this update pertains to.
pub session_id: SessionId,
/// The actual update content.
Expand All @@ -65,8 +65,8 @@
pub meta: Option<Meta>,
}

impl SessionNotification {
impl UpdateSessionNotification {
/// Builds [`SessionNotification`] with the required notification fields set; optional fields start unset or empty.

Check warning on line 69 in agent-client-protocol-schema/src/v2/client.rs

View workflow job for this annotation

GitHub Actions / Build

unresolved link to `SessionNotification`
#[must_use]
pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
Self {
Expand Down Expand Up @@ -743,13 +743,13 @@
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ContentChunk {
/// A single item of content
pub content: ContentBlock,
/// A unique identifier for the message this chunk belongs to.
///
/// All chunks belonging to the same message share the same `messageId`.
/// A change in `messageId` indicates a new message has started.
pub message_id: MessageId,
/// A single item of content
pub content: 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
/// these keys.
Expand Down Expand Up @@ -1424,7 +1424,6 @@
#[non_exhaustive]
pub struct RequestPermissionResponse {
/// The user's decision on the permission request.
// This extra-level is unfortunately needed because the output must be an object
pub outcome: RequestPermissionOutcome,
/// 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 @@ -1547,7 +1546,7 @@
#[serde_as(deserialize_as = "DefaultOnError")]
#[schemars(extend("x-deserialize-default-on-error" = true))]
#[serde(default)]
pub auth: AuthCapabilities,
pub auth: Option<AuthCapabilities>,
/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
Expand Down Expand Up @@ -1608,8 +1607,8 @@
/// in its `InitializeResponse`.
#[cfg(feature = "unstable_auth_methods")]
#[must_use]
pub fn auth(mut self, auth: AuthCapabilities) -> Self {
self.auth = auth;
pub fn auth(mut self, auth: impl IntoOption<AuthCapabilities>) -> Self {
self.auth = auth.into_option();
self
}

Expand Down Expand Up @@ -1926,11 +1925,11 @@
/// Successful result returned for a `mcp/disconnect` request.
#[cfg(feature = "unstable_mcp_over_acp")]
DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
/// Successful result returned by an extension method outside the core ACP method set.
ExtMethodResponse(ExtResponse),
/// Successful result returned by an MCP-over-ACP `mcp/message` request.
#[cfg(feature = "unstable_mcp_over_acp")]
MessageMcpResponse(MessageMcpResponse),
/// Successful result returned by an extension method outside the core ACP method set.
ExtMethodResponse(ExtResponse),
}

/// All possible notifications that an agent can send to a client.
Expand All @@ -1956,7 +1955,7 @@
/// stop reason.
///
/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-lifecycle#3-agent-reports-output)
SessionNotification(Box<SessionNotification>),
UpdateSessionNotification(Box<UpdateSessionNotification>),
/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
Expand Down Expand Up @@ -1986,7 +1985,7 @@
#[must_use]
pub fn method(&self) -> &str {
match self {
Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
Self::UpdateSessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
#[cfg(feature = "unstable_elicitation")]
Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
#[cfg(feature = "unstable_mcp_over_acp")]
Expand All @@ -2010,7 +2009,7 @@
}))
.unwrap();

assert_eq!(capabilities.auth, AuthCapabilities::default());
assert_eq!(capabilities.auth, None);
}

#[test]
Expand Down
28 changes: 15 additions & 13 deletions agent-client-protocol-schema/src/v2/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ impl IntoV2 for crate::v1::ProtocolLevelNotification {
}
}

impl IntoV1Many for super::SessionNotification {
impl IntoV1Many for super::UpdateSessionNotification {
type Output = crate::v1::SessionNotification;

fn into_v1_many(self) -> Result<Vec<Self::Output>> {
Expand All @@ -975,15 +975,15 @@ impl IntoV1Many for super::SessionNotification {
}

impl IntoV2 for crate::v1::SessionNotification {
type Output = super::SessionNotification;
type Output = super::UpdateSessionNotification;

fn into_v2(self) -> Result<Self::Output> {
let Self {
session_id,
update,
meta,
} = self;
Ok(super::SessionNotification {
Ok(super::UpdateSessionNotification {
session_id: session_id.into_v2()?,
update: update.into_v2()?,
meta: meta.into_v2()?,
Expand Down Expand Up @@ -1907,7 +1907,7 @@ impl IntoV1 for super::ClientCapabilities {
#[cfg(feature = "unstable_plan_operations")]
plan: None,
#[cfg(feature = "unstable_auth_methods")]
auth: auth.into_v1()?,
auth: auth.map(IntoV1::into_v1).transpose()?.unwrap_or_default(),
#[cfg(feature = "unstable_elicitation")]
elicitation: into_v1_default_on_error(elicitation),
#[cfg(feature = "unstable_nes")]
Expand Down Expand Up @@ -1942,7 +1942,7 @@ impl IntoV2 for crate::v1::ClientCapabilities {
} = self;
Ok(super::ClientCapabilities {
#[cfg(feature = "unstable_auth_methods")]
auth: auth.into_v2()?,
auth: Some(auth.into_v2()?),
#[cfg(feature = "unstable_elicitation")]
elicitation: into_v2_default_on_error(elicitation),
#[cfg(feature = "unstable_nes")]
Expand Down Expand Up @@ -2169,7 +2169,7 @@ impl IntoV1Many for super::AgentNotification {

fn into_v1_many(self) -> Result<Vec<Self::Output>> {
Ok(match self {
Self::SessionNotification(value) => {
Self::UpdateSessionNotification(value) => {
return value
.into_v1_many()?
.into_iter()
Expand Down Expand Up @@ -2203,7 +2203,7 @@ impl IntoV2 for crate::v1::AgentNotification {
fn into_v2(self) -> Result<Self::Output> {
Ok(match self {
Self::SessionNotification(value) => {
super::AgentNotification::SessionNotification(Box::new(value.into_v2()?))
super::AgentNotification::UpdateSessionNotification(Box::new(value.into_v2()?))
}
#[cfg(feature = "unstable_elicitation")]
Self::CompleteElicitationNotification(value) => {
Expand Down Expand Up @@ -9641,7 +9641,7 @@ mod tests {
for update in cases {
let notification = v1::SessionNotification::new("sess", update);
let original_json = serde_json::to_value(&notification).expect("v1 serialize");
let as_v2: v2::SessionNotification =
let as_v2: v2::UpdateSessionNotification =
v1_to_v2(notification.clone()).expect("v1 -> v2 conversion");
let v2_json = serde_json::to_value(&as_v2).expect("v2 serialize");
assert_eq!(
Expand All @@ -9665,7 +9665,8 @@ mod tests {
"sess",
v1::SessionUpdate::ToolCall(v1::ToolCall::new("tc", "title")),
);
let create_v2: v2::SessionNotification = v1_to_v2(create).expect("v1 -> v2 conversion");
let create_v2: v2::UpdateSessionNotification =
v1_to_v2(create).expect("v1 -> v2 conversion");
assert!(matches!(
create_v2.update,
v2::SessionUpdate::ToolCallUpdate(_)
Expand All @@ -9689,7 +9690,8 @@ mod tests {
v1::ToolCallUpdateFields::new().status(v1::ToolCallStatus::Completed),
)),
);
let update_v2: v2::SessionNotification = v1_to_v2(update).expect("v1 -> v2 conversion");
let update_v2: v2::UpdateSessionNotification =
v1_to_v2(update).expect("v1 -> v2 conversion");
assert!(matches!(
update_v2.update,
v2::SessionUpdate::ToolCallUpdate(_)
Expand Down Expand Up @@ -9765,7 +9767,7 @@ mod tests {

#[test]
fn v2_full_message_session_notification_fans_out_to_v1_chunk_notifications() {
let notification = v2::SessionNotification::new(
let notification = v2::UpdateSessionNotification::new(
"sess",
v2::SessionUpdate::AgentMessage(v2::AgentMessage::new("msg_agent").content(vec![
v2::ContentBlock::Text(v2::TextContent::new("hello")),
Expand Down Expand Up @@ -9803,8 +9805,8 @@ mod tests {
fn v2_json_rpc_agent_notification_fans_out_to_v1_chunk_notifications() {
let message = v2::JsonRpcMessage::wrap(v2::Notification {
method: "session/update".into(),
params: Some(v2::AgentNotification::SessionNotification(Box::new(
v2::SessionNotification::new(
params: Some(v2::AgentNotification::UpdateSessionNotification(Box::new(
v2::UpdateSessionNotification::new(
"sess",
v2::SessionUpdate::AgentMessage(v2::AgentMessage::new("msg_agent").content(
vec![
Expand Down
8 changes: 3 additions & 5 deletions docs/protocol/v2/draft/schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d
<ResponseField name="capabilities" type={<a href="#clientcapabilities">ClientCapabilities</a>} >
Capabilities supported by the client.

- Default: `{"auth":{}}`
- Default: `{}`

</ResponseField>
<ResponseField name="info" type={<a href="#implementation">Implementation</a>} required>
Expand Down Expand Up @@ -2005,7 +2005,7 @@ stop reason.

See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/v2/draft/prompt-lifecycle#3-agent-reports-output)

#### <span class="font-mono">SessionNotification</span>
#### <span class="font-mono">UpdateSessionNotification</span>

Notification containing a session update from the agent.

Expand Down Expand Up @@ -2807,7 +2807,7 @@ these keys.
See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility)

</ResponseField>
<ResponseField name="auth" type={<a href="#authcapabilities">AuthCapabilities</a>} >
<ResponseField name="auth" type={<><span><a href="#authcapabilities">AuthCapabilities</a></span><span> | null</span></>} >
**UNSTABLE**

This capability is not part of the spec yet, and may be removed or changed at any point.
Expand All @@ -2816,8 +2816,6 @@ Authentication capabilities supported by the client.
Determines which authentication method types the agent may include
in its `InitializeResponse`.

- Default: `{}`

</ResponseField>
<ResponseField name="elicitation" type={<><span><a href="#elicitationcapabilities">ElicitationCapabilities</a></span><span> | null</span></>} >
**UNSTABLE**
Expand Down
2 changes: 1 addition & 1 deletion docs/protocol/v2/schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ stop reason.

See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/v2/prompt-lifecycle#3-agent-reports-output)

#### <span class="font-mono">SessionNotification</span>
#### <span class="font-mono">UpdateSessionNotification</span>

Notification containing a session update from the agent.

Expand Down
6 changes: 5 additions & 1 deletion schema-generator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1915,7 +1915,11 @@ starting with '$/' it is free to ignore the notification."
}
"fs/write_text_file" => self.client.get("WriteTextFileRequest").unwrap(),
"fs/read_text_file" => self.client.get("ReadTextFileRequest").unwrap(),
"session/update" => self.client.get("SessionNotification").unwrap(),
"session/update" => self
.client
.get("UpdateSessionNotification")
.or_else(|| self.client.get("SessionNotification"))
.unwrap(),
"terminal/create" => self.client.get("CreateTerminalRequest").unwrap(),
"terminal/output" => self.client.get("TerminalOutputRequest").unwrap(),
"terminal/release" => self.client.get("ReleaseTerminalRequest").unwrap(),
Expand Down
12 changes: 6 additions & 6 deletions schema/v1/schema.unstable.json
Original file line number Diff line number Diff line change
Expand Up @@ -7746,20 +7746,20 @@
]
},
{
"title": "ExtMethodResponse",
"description": "Successful result returned by an extension method outside the core ACP method set.",
"title": "MessageMcpResponse",
"description": "Successful result returned by an MCP-over-ACP `mcp/message` request.",
"allOf": [
{
"$ref": "#/$defs/ExtResponse"
"$ref": "#/$defs/MessageMcpResponse"
}
]
},
{
"title": "MessageMcpResponse",
"description": "Successful result returned by an MCP-over-ACP `mcp/message` request.",
"title": "ExtMethodResponse",
"description": "Successful result returned by an extension method outside the core ACP method set.",
"allOf": [
{
"$ref": "#/$defs/MessageMcpResponse"
"$ref": "#/$defs/ExtResponse"
}
]
}
Expand Down
20 changes: 10 additions & 10 deletions schema/v2/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2685,11 +2685,11 @@
"description": "All possible notifications that an agent can send to a client.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly.\n\nNotifications do not expect a response.",
"anyOf": [
{
"title": "SessionNotification",
"title": "UpdateSessionNotification",
"description": "Handles session update notifications from the agent.\n\nThis is a notification endpoint (no response expected) that receives\nreal-time updates about session progress, including message updates,\nmessage chunks, tool calls, and execution plans.\n\nNote: Clients SHOULD continue accepting tool call updates even after\nsending a `session/cancel` notification, as the agent may send final\nupdates before reporting an idle `state_update` with the cancelled\nstop reason.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/v2/prompt-lifecycle#3-agent-reports-output)",
"allOf": [
{
"$ref": "#/$defs/SessionNotification"
"$ref": "#/$defs/UpdateSessionNotification"
}
]
},
Expand All @@ -2713,7 +2713,7 @@
"required": ["method"],
"x-docs-ignore": true
},
"SessionNotification": {
"UpdateSessionNotification": {
"description": "Notification containing a session update from the agent.\n\nUsed to stream real-time progress and results during prompt processing.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/v2/prompt-lifecycle#3-agent-reports-output)",
"type": "object",
"properties": {
Expand Down Expand Up @@ -3141,19 +3141,19 @@
"description": "A streamed item of content",
"type": "object",
"properties": {
"content": {
"description": "A single item of content",
"messageId": {
"description": "A unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started.",
"allOf": [
{
"$ref": "#/$defs/ContentBlock"
"$ref": "#/$defs/MessageId"
}
]
},
"messageId": {
"description": "A unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started.",
"content": {
"description": "A single item of content",
"allOf": [
{
"$ref": "#/$defs/MessageId"
"$ref": "#/$defs/ContentBlock"
}
]
},
Expand All @@ -3164,7 +3164,7 @@
"additionalProperties": true
}
},
"required": ["content", "messageId"]
"required": ["messageId", "content"]
},
"UserMessage": {
"description": "A user message upsert.\n\nOnly [`UserMessage::message_id`] is required. Other fields have patch\nsemantics: omitted fields leave the existing message value unchanged, `null`\nclears or unsets the value, and concrete values replace the previous value.\nFor a new `messageId`, omitted fields use client defaults. `content` is\nreplaced as a whole array; send `[]` or `null` to clear it.\n\nMessage updates and chunks are applied in the order they are received. When\na `user_message` update includes `content`, that array replaces any content\npreviously accumulated for the message, including content from earlier\nchunks. Later chunks with the same `messageId` append to the current\ncontent.",
Expand Down
Loading