Skip to content
Draft
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
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ categories = ["development-tools", "api-bindings"]
include = ["/rust/**/*.rs", "/README.md", "/LICENSE", "/Cargo.toml"]

[features]
unstable = ["unstable_session_model", "unstable_session_list"]
unstable = ["unstable_session_model", "unstable_session_list", "unstable_session_fork"]
unstable_session_model = []
unstable_session_list = []
unstable_session_fork = []

[lib]
path = "rust/acp.rs"
Expand Down
187 changes: 187 additions & 0 deletions rust/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,121 @@ impl LoadSessionResponse {
}
}

// Fork session

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Request parameters for forking an existing session.
///
/// Creates a new session based on the context of an existing one, allowing
/// operations like generating summaries without affecting the original session's history.
///
/// Only available if the Agent supports the `session.fork` capability.
#[cfg(feature = "unstable_session_fork")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ForkSessionRequest {
/// The ID of the session to fork.
pub session_id: SessionId,
/// Extension point for implementations
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<serde_json::Value>,
}

#[cfg(feature = "unstable_session_fork")]
impl ForkSessionRequest {
pub fn new(session_id: impl Into<SessionId>) -> Self {
Self {
session_id: session_id.into(),
meta: None,
}
}

/// Extension point for implementations
#[must_use]
pub fn meta(mut self, meta: serde_json::Value) -> Self {
self.meta = Some(meta);
self
}
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Response from forking an existing session.
#[cfg(feature = "unstable_session_fork")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ForkSessionResponse {
/// Unique identifier for the newly created forked session.
pub session_id: SessionId,
/// Initial mode state if supported by the Agent
///
/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
#[serde(skip_serializing_if = "Option::is_none")]
pub modes: Option<SessionModeState>,
/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Initial model state if supported by the Agent
#[cfg(feature = "unstable_session_model")]
#[serde(skip_serializing_if = "Option::is_none")]
pub models: Option<SessionModelState>,
/// Extension point for implementations
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<serde_json::Value>,
}

#[cfg(feature = "unstable_session_fork")]
impl ForkSessionResponse {
#[must_use]
pub fn new(session_id: impl Into<SessionId>) -> Self {
Self {
session_id: session_id.into(),
modes: None,
#[cfg(feature = "unstable_session_model")]
models: None,
meta: None,
}
}

/// Initial mode state if supported by the Agent
///
/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
#[must_use]
pub fn modes(mut self, modes: SessionModeState) -> Self {
self.modes = Some(modes);
self
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Initial model state if supported by the Agent
#[cfg(feature = "unstable_session_model")]
#[must_use]
pub fn models(mut self, models: SessionModelState) -> Self {
self.models = Some(models);
self
}

/// Extension point for implementations
#[must_use]
pub fn meta(mut self, meta: serde_json::Value) -> Self {
self.meta = Some(meta);
self
}
}

// List sessions

/// **UNSTABLE**
Expand Down Expand Up @@ -1427,6 +1542,14 @@ pub struct SessionCapabilities {
#[cfg(feature = "unstable_session_list")]
#[serde(skip_serializing_if = "Option::is_none")]
pub list: Option<SessionListCapabilities>,
/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Whether the agent supports `session/fork`.
#[cfg(feature = "unstable_session_fork")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fork: Option<SessionForkCapabilities>,
/// Extension point for implementations
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<serde_json::Value>,
Expand All @@ -1446,6 +1569,14 @@ impl SessionCapabilities {
self
}

#[cfg(feature = "unstable_session_fork")]
/// Whether the agent supports `session/fork`.
#[must_use]
pub fn fork(mut self, fork: SessionForkCapabilities) -> Self {
self.fork = Some(fork);
self
}

/// Extension point for implementations
#[must_use]
pub fn meta(mut self, meta: serde_json::Value) -> Self {
Expand Down Expand Up @@ -1482,6 +1613,37 @@ impl SessionListCapabilities {
}
}

/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Capabilities for the `session/fork` method.
///
/// By supplying `{}` it means that the agent supports forking of sessions.
#[cfg(feature = "unstable_session_fork")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[non_exhaustive]
pub struct SessionForkCapabilities {
/// Extension point for implementations
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<serde_json::Value>,
}

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

/// Extension point for implementations
#[must_use]
pub fn meta(mut self, meta: serde_json::Value) -> Self {
self.meta = Some(meta);
self
}
}

/// Prompt capabilities supported by the agent in `session/prompt` requests.
///
/// Baseline agent functionality requires support for [`ContentBlock::Text`]
Expand Down Expand Up @@ -1625,6 +1787,9 @@ pub struct AgentMethodNames {
/// Method for listing existing sessions.
#[cfg(feature = "unstable_session_list")]
pub session_list: &'static str,
/// Method for forking an existing session.
#[cfg(feature = "unstable_session_fork")]
pub session_fork: &'static str,
}

/// Constant containing all agent method names.
Expand All @@ -1640,6 +1805,8 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
session_set_model: SESSION_SET_MODEL_METHOD_NAME,
#[cfg(feature = "unstable_session_list")]
session_list: SESSION_LIST_METHOD_NAME,
#[cfg(feature = "unstable_session_fork")]
session_fork: SESSION_FORK_METHOD_NAME,
};

/// Method name for the initialize request.
Expand All @@ -1662,6 +1829,9 @@ pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
/// Method name for listing existing sessions.
#[cfg(feature = "unstable_session_list")]
pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
/// Method name for forking an existing session.
#[cfg(feature = "unstable_session_fork")]
pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";

/// All possible requests that a client can send to an agent.
///
Expand Down Expand Up @@ -1730,6 +1900,19 @@ pub enum ClientRequest {
///
/// The agent should return metadata about sessions with optional filtering and pagination support.
ListSessionsRequest(ListSessionsRequest),
#[cfg(feature = "unstable_session_fork")]
/// **UNSTABLE**
///
/// This capability is not part of the spec yet, and may be removed or changed at any point.
///
/// Forks an existing session to create a new independent session.
///
/// This method is only available if the agent advertises the `session.fork` capability.
///
/// The agent should create a new session with the same conversation context as the
/// original, allowing operations like generating summaries without affecting the
/// original session's history.
ForkSessionRequest(ForkSessionRequest),
/// Sets the current mode for a session.
///
/// Allows switching between different agent modes (e.g., "ask", "architect", "code")
Expand Down Expand Up @@ -1783,6 +1966,8 @@ impl ClientRequest {
Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
#[cfg(feature = "unstable_session_list")]
Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
#[cfg(feature = "unstable_session_fork")]
Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
#[cfg(feature = "unstable_session_model")]
Expand All @@ -1809,6 +1994,8 @@ pub enum AgentResponse {
LoadSessionResponse(#[serde(default)] LoadSessionResponse),
#[cfg(feature = "unstable_session_list")]
ListSessionsResponse(ListSessionsResponse),
#[cfg(feature = "unstable_session_fork")]
ForkSessionResponse(ForkSessionResponse),
SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
PromptResponse(PromptResponse),
#[cfg(feature = "unstable_session_model")]
Expand Down
1 change: 1 addition & 0 deletions rust/bin/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,7 @@ and control access to resources."
"session/new" => self.agent_methods.get("NewSessionRequest").unwrap(),
"session/load" => self.agent_methods.get("LoadSessionRequest").unwrap(),
"session/list" => self.agent_methods.get("ListSessionsRequest").unwrap(),
"session/fork" => self.agent_methods.get("ForkSessionRequest").unwrap(),
"session/set_mode" => self.agent_methods.get("SetSessionModeRequest").unwrap(),
"session/prompt" => self.agent_methods.get("PromptRequest").unwrap(),
"session/cancel" => self.agent_methods.get("CancelNotification").unwrap(),
Expand Down
4 changes: 4 additions & 0 deletions rust/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ impl Side for AgentSide {
m if m == AGENT_METHOD_NAMES.session_list => serde_json::from_str(params.get())
.map(ClientRequest::ListSessionsRequest)
.map_err(Into::into),
#[cfg(feature = "unstable_session_fork")]
m if m == AGENT_METHOD_NAMES.session_fork => serde_json::from_str(params.get())
.map(ClientRequest::ForkSessionRequest)
.map_err(Into::into),
m if m == AGENT_METHOD_NAMES.session_set_mode => serde_json::from_str(params.get())
.map(ClientRequest::SetSessionModeRequest)
.map_err(Into::into),
Expand Down