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
14 changes: 11 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@ categories = ["development-tools", "api-bindings"]
include = ["/src/**/*.rs", "/README.md", "/LICENSE", "/Cargo.toml"]

[features]
unstable = ["unstable_session_model", "unstable_session_list", "unstable_session_fork", "unstable_session_resume", "unstable_cancel_request"]
unstable = [
"unstable_cancel_request",
"unstable_session_fork",
"unstable_session_info_update",
"unstable_session_list",
"unstable_session_model",
"unstable_session_resume",
]
unstable_cancel_request = []
unstable_session_model = []
unstable_session_list = []
unstable_session_fork = []
unstable_session_info_update = []
unstable_session_list = []
unstable_session_model = []
unstable_session_resume = []

[[bin]]
Expand Down
51 changes: 51 additions & 0 deletions docs/protocol/draft/schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2926,6 +2926,32 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte
ISO 8601 timestamp of last activity
</ResponseField>

## <span class="font-mono">SessionInfoUpdate</span>

Update to session metadata. All fields are optional to support partial updates.

Agents send this notification to update session information like title or custom metadata.
This allows clients to display dynamic session names and track session state changes.

**Type:** Object

**Properties:**

<ResponseField name="_meta" type={"object | null"} >
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.

See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)

</ResponseField>
<ResponseField name="title" type={"string | null"} >
Human-readable title for the session. Set to null to clear.
</ResponseField>
<ResponseField name="updatedAt" type={"string | null"} >
ISO 8601 timestamp of last activity. Set to null to clear.
</ResponseField>

## <span class="font-mono">SessionListCapabilities</span>

Capabilities for the `session/list` method.
Expand Down Expand Up @@ -3288,6 +3314,31 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte
</Expandable>
</ResponseField>

<ResponseField name="session_info_update" type="object">
Session metadata has been updated (title, timestamps, custom metadata)

<Expandable title="Properties">

<ResponseField name="_meta" type={"object | null"} >
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.

See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)

</ResponseField>
<ResponseField name="sessionUpdate" type={"string"} required>
</ResponseField>
<ResponseField name="title" type={"string | null"} >
Human-readable title for the session. Set to null to clear.
</ResponseField>
<ResponseField name="updatedAt" type={"string | null"} >
ISO 8601 timestamp of last activity. Set to null to clear.
</ResponseField>

</Expandable>
</ResponseField>

## <span class="font-mono">StopReason</span>

Reasons why an agent stops processing a prompt turn.
Expand Down
35 changes: 35 additions & 0 deletions schema/schema.unstable.json
Original file line number Diff line number Diff line change
Expand Up @@ -2460,6 +2460,25 @@
"required": ["sessionId", "cwd"],
"type": "object"
},
"SessionInfoUpdate": {
"description": "Update to session metadata. All fields are optional to support partial updates.\n\nAgents send this notification to update session information like title or custom metadata.\nThis allows clients to display dynamic session names and track session state changes.",
"properties": {
"_meta": {
"additionalProperties": true,
"description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)",
"type": ["object", "null"]
},
"title": {
"description": "Human-readable title for the session. Set to null to clear.",
"type": ["string", "null"]
},
"updatedAt": {
"description": "ISO 8601 timestamp of last activity. Set to null to clear.",
"type": ["string", "null"]
}
},
"type": "object"
},
"SessionListCapabilities": {
"description": "Capabilities for the `session/list` method.\n\nBy supplying `{}` it means that the agent supports listing of sessions.\n\nFurther capabilities can be added in the future for other means of filtering or searching the list.",
"properties": {
Expand Down Expand Up @@ -2724,6 +2743,22 @@
},
"required": ["sessionUpdate"],
"type": "object"
},
{
"allOf": [
{
"$ref": "#/$defs/SessionInfoUpdate"
}
],
"description": "Session metadata has been updated (title, timestamps, custom metadata)",
"properties": {
"sessionUpdate": {
"const": "session_info_update",
"type": "string"
}
},
"required": ["sessionUpdate"],
"type": "object"
}
]
},
Expand Down
124 changes: 124 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use crate::{
ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta, Plan, SessionId,
SessionModeId, ToolCall, ToolCallUpdate,
};
#[cfg(feature = "unstable_session_info_update")]
use crate::{IntoMaybeUndefined, MaybeUndefined};

// Session updates

Expand Down Expand Up @@ -90,6 +92,9 @@ pub enum SessionUpdate {
///
/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
CurrentModeUpdate(CurrentModeUpdate),
#[cfg(feature = "unstable_session_info_update")]
/// Session metadata has been updated (title, timestamps, custom metadata)
SessionInfoUpdate(SessionInfoUpdate),
}

/// The current mode of the session has changed
Expand Down Expand Up @@ -131,6 +136,63 @@ impl CurrentModeUpdate {
}
}

/// Update to session metadata. All fields are optional to support partial updates.
///
/// Agents send this notification to update session information like title or custom metadata.
/// This allows clients to display dynamic session names and track session state changes.
#[cfg(feature = "unstable_session_info_update")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionInfoUpdate {
/// Human-readable title for the session. Set to null to clear.
#[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
pub title: MaybeUndefined<String>,
/// ISO 8601 timestamp of last activity. Set to null to clear.
#[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
pub updated_at: MaybeUndefined<String>,
/// 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.
///
/// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}

#[cfg(feature = "unstable_session_info_update")]
impl SessionInfoUpdate {
#[must_use]
pub fn new() -> Self {
Self::default()
}

/// Human-readable title for the session. Set to null to clear.
#[must_use]
pub fn title(mut self, title: impl IntoMaybeUndefined<String>) -> Self {
self.title = title.into_maybe_undefined();
self
}

/// ISO 8601 timestamp of last activity. Set to null to clear.
#[must_use]
pub fn updated_at(mut self, updated_at: impl IntoMaybeUndefined<String>) -> Self {
self.updated_at = updated_at.into_maybe_undefined();
self
}

/// 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.
///
/// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}

/// A streamed item of content
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -1587,3 +1649,65 @@ impl AgentNotification {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[cfg(feature = "unstable_session_info_update")]
#[test]
fn test_serialization_behavior() {
use serde_json::json;

assert_eq!(
serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
SessionInfoUpdate {
title: MaybeUndefined::Undefined,
updated_at: MaybeUndefined::Undefined,
meta: None
}
);
assert_eq!(
serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
.unwrap(),
SessionInfoUpdate {
title: MaybeUndefined::Null,
updated_at: MaybeUndefined::Null,
meta: None
}
);
assert_eq!(
serde_json::from_value::<SessionInfoUpdate>(
json!({"title": "title", "updatedAt": "timestamp"})
)
.unwrap(),
SessionInfoUpdate {
title: MaybeUndefined::Value("title".to_string()),
updated_at: MaybeUndefined::Value("timestamp".to_string()),
meta: None
}
);

assert_eq!(
serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
json!({})
);
assert_eq!(
serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
json!({"title": "title"})
);
assert_eq!(
serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
json!({"title": null})
);
assert_eq!(
serde_json::to_value(
SessionInfoUpdate::new()
.title("title")
.title(MaybeUndefined::Undefined)
)
.unwrap(),
json!({})
);
}
}