From 659687a4cd15c9f6626cacb2a0482823525de691 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Fri, 12 Sep 2025 22:09:35 -0300 Subject: [PATCH 1/2] Stabilize session modes --- docs/docs.json | 1 + docs/protocol/schema.mdx | 88 +++++++++++------ docs/protocol/session-modes.mdx | 166 ++++++++++++++++++++++++++++++++ rust/acp.rs | 2 - rust/agent.rs | 57 +++++------ rust/client.rs | 5 +- rust/rpc_tests.rs | 1 - rust/tool_call.rs | 5 +- schema/schema.json | 36 ++++--- typescript/schema.ts | 111 ++++++++------------- 10 files changed, 317 insertions(+), 155 deletions(-) create mode 100644 docs/protocol/session-modes.mdx diff --git a/docs/docs.json b/docs/docs.json index 14f2dbd3..9f253586 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -58,6 +58,7 @@ "protocol/file-system", "protocol/terminals", "protocol/agent-plan", + "protocol/session-modes", "protocol/extensibility", "protocol/schema" ] diff --git a/docs/protocol/schema.mdx b/docs/protocol/schema.mdx index f45ff132..337861de 100644 --- a/docs/protocol/schema.mdx +++ b/docs/protocol/schema.mdx @@ -234,9 +234,9 @@ Response from loading an existing session. Extension point for implementations SessionModeState | null} > - **UNSTABLE** + Initial mode state if supported by the Agent -This field is not part of the spec, and may be removed or changed at any point. +See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) @@ -302,9 +302,9 @@ See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol Extension point for implementations SessionModeState | null} > - **UNSTABLE** + Initial mode state if supported by the Agent -This field is not part of the spec, and may be removed or changed at any point. +See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) SessionId} required> @@ -386,6 +386,49 @@ See protocol docs: [Check for Completion](https://agentclientprotocol.com/protoc Indicates why the agent stopped processing the turn. + +### session/set_mode + +**UNSTABLE** + +This method is not part of the spec, and may be removed or changed at any point. + +#### SetSessionModeRequest + +Request parameters for setting a session mode. + +**Type:** Object + +**Properties:** + + + Extension point for implementations + +SessionModeId} + required +> + The ID of the mode to set. + +SessionId} + required +> + The ID of the session to set the mode for. + + +#### SetSessionModeResponse + +Response to `session/set_mode` method. + +**Type:** Object + +**Properties:** + + + ## Client Defines the interface that ACP-compliant clients must implement. @@ -1885,9 +1928,9 @@ See protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session ## SessionMode -**UNSTABLE** +A mode the agent can operate in. -This type is not part of the spec, and may be removed or changed at any point. +See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) **Type:** Object @@ -1906,17 +1949,13 @@ This type is not part of the spec, and may be removed or changed at any point. ## SessionModeId -**UNSTABLE** - -This type is not part of the spec, and may be removed or changed at any point. +Unique identifier for a Session Mode. **Type:** `string` ## SessionModeState -**UNSTABLE** - -This type is not part of the spec, and may be removed or changed at any point. +The set of modes and the one currently active. **Type:** Object @@ -1936,12 +1975,16 @@ This type is not part of the spec, and may be removed or changed at any point. } required -> +> + The set of modes that the Agent can operate in + SessionModeId} required -> +> + The current mode the Agent is in. + ## SessionUpdate @@ -2184,18 +2227,6 @@ The current mode of the session has changed -## SetSessionModeResponse - -**UNSTABLE** - -This type is not part of the spec, and may be removed or changed at any point. - -**Type:** Object - -**Properties:** - - - ## StopReason Reasons why an agent stops processing a prompt turn. @@ -2576,10 +2607,7 @@ See protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-call Retrieving external data. -**UNSTABLE** - -This tool kind is not part of the spec and may be removed at any point. - + Switching the current session mode. Other tool types (default). diff --git a/docs/protocol/session-modes.mdx b/docs/protocol/session-modes.mdx new file mode 100644 index 00000000..233d2102 --- /dev/null +++ b/docs/protocol/session-modes.mdx @@ -0,0 +1,166 @@ +--- +title: "Session Modes" +description: "How agents can operate in different modes" +--- + +Agents can provide a set of modes they can operate in. Modes often affect the system prompts used, the availability of tools, and whether they request permission before running. + +## Initial state + +During [Session Setup](./session-setup) the Agent **MAY** return a list of modes it can operate in and the currently active mode: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "sessionId": "sess_abc123def456", + "modes": { + "currentModeId": "ask", + "availableModes": [ + { + "id": "ask", + "name": "Ask", + "description": "Request permission before making any changes" + }, + { + "id": "architect", + "name": "Architect", + "description": "Design and plan software systems without implementation" + }, + { + "id": "code", + "name": "Code", + "description": "Write and modify code with full tool access" + }, + ] + } + } +} +``` + + + The current mode state for the session + + +### SessionModeState + + + The ID of the mode that is currently active + + + + The set of modes that the Agent can operate in + + +### SessionMode + + + Unique identifier for this mode + + + + Human-readable name of the mode + + + + Optional description providing more details about what this mode does + + +## Setting the current mode + +The current mode can be changed at any point during a session, whether the Agent is idle or generating a response. + +### From the Client + +Typically, Clients display the available modes to the user and allow them to change the current one, which they can do by calling the [`session/set_mode`](./schema#session%2Fset-mode) method. + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "session/set_mode", + "params": { + "sessionId": "sess_abc123def456", + "modeId": "code" + } +} +``` + + + The ID of the session to set the mode for + + + + The ID of the mode to switch to. Must be one of the modes listed in `availableModes` + + +### From the Agent + +The Agent can also change its own mode and let the Client know by sending the `current_mode_update` session notification: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "current_mode_update", + "modeId": "code" + } + } +} +``` + +#### Exiting plan modes + +A common case where an Agent might switch modes is from within a special "exit mode" tool that can be provided to the language model during plan/architect modes. The language model can call this tool when it determines it's ready to start implementing a solution. + +This "switch mode" tool will usually request permission before running, which it can do just like any other tool: + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "method": "session/request_permission", + "params": { + "sessionId": "sess_abc123def456", + "toolCall": { + "toolCallId": "call_switch_mode_001", + "title": "Ready for implementation", + "kind": "switch_mode", + "status": "pending", + "content": [ + { + "type": "text", + "text": "## Implementation Plan..." + } + ] + }, + "options": [ + { + "optionId": "code", + "name": "Yes, and auto-accept all actions", + "kind": "allow_always" + }, + { + "optionId": "ask", + "name": "Yes, and manually accept actions", + "kind": "allow_once" + }, + { + "optionId": "reject", + "name": "No, stay in architect mode", + "kind": "reject_once" + } + ] + } +} +``` + +When an option is chosen, the tool runs, setting the mode and sending the `current_mode_update` notification mentioned above. + + + Learn more about permission requests + diff --git a/rust/acp.rs b/rust/acp.rs index 84e5ce95..caffe4f2 100644 --- a/rust/acp.rs +++ b/rust/acp.rs @@ -211,7 +211,6 @@ impl Agent for ClientSideConnection { .map(|value| value.unwrap_or_default()) } - #[cfg(feature = "unstable")] async fn set_session_mode( &self, arguments: SetSessionModeRequest, @@ -619,7 +618,6 @@ impl Side for AgentSide { SESSION_LOAD_METHOD_NAME => serde_json::from_str(params.get()) .map(ClientRequest::LoadSessionRequest) .map_err(Into::into), - #[cfg(feature = "unstable")] SESSION_SET_MODE_METHOD_NAME => serde_json::from_str(params.get()) .map(ClientRequest::SetSessionModeRequest) .map_err(Into::into), diff --git a/rust/agent.rs b/rust/agent.rs index 3d1a3019..60d5a1a5 100644 --- a/rust/agent.rs +++ b/rust/agent.rs @@ -79,10 +79,19 @@ pub trait Agent { arguments: LoadSessionRequest, ) -> impl Future>; - /// **UNSTABLE** + /// Sets the current mode for a session. /// - /// This method is not part of the spec, and may be removed or changed at any point. - #[cfg(feature = "unstable")] + /// Allows switching between different agent modes (e.g., "ask", "architect", "code") + /// that affect system prompts, tool availability, and permission behaviors. + /// + /// The mode must be one of the modes advertised in `availableModes` during session + /// creation or loading. Agents may also change modes autonomously and notify the + /// client via `current_mode_update` notifications. + /// + /// This method can be called at any time during a session, whether the Agent is + /// idle or actively generating a response. + /// + /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) fn set_session_mode( &self, arguments: SetSessionModeRequest, @@ -264,9 +273,9 @@ pub struct NewSessionResponse { /// /// Used in all subsequent requests for this conversation. pub session_id: SessionId, - /// **UNSTABLE** + /// Initial mode state if supported by the Agent /// - /// This field is not part of the spec, and may be removed or changed at any point. + /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) #[serde(default, skip_serializing_if = "Option::is_none")] pub modes: Option, /// Extension point for implementations @@ -301,9 +310,9 @@ pub struct LoadSessionRequest { #[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))] #[serde(rename_all = "camelCase")] pub struct LoadSessionResponse { - /// **UNSTABLE** + /// Initial mode state if supported by the Agent /// - /// This field is not part of the spec, and may be removed or changed at any point. + /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) #[serde(default, skip_serializing_if = "Option::is_none")] pub modes: Option, /// Extension point for implementations @@ -313,22 +322,22 @@ pub struct LoadSessionResponse { // Session modes -/// **UNSTABLE** -/// -/// This type is not part of the spec, and may be removed or changed at any point. +/// The set of modes and the one currently active. #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct SessionModeState { + /// The current mode the Agent is in. pub current_mode_id: SessionModeId, + /// The set of modes that the Agent can operate in pub available_modes: Vec, /// Extension point for implementations #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")] pub meta: Option, } -/// **UNSTABLE** +/// A mode the agent can operate in. /// -/// This type is not part of the spec, and may be removed or changed at any point. +/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct SessionMode { @@ -341,11 +350,9 @@ pub struct SessionMode { pub meta: Option, } -/// **UNSTABLE** -/// -/// This type is not part of the spec, and may be removed or changed at any point. +/// Unique identifier for a Session Mode. #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)] -#[serde(rename_all = "camelCase")] +#[serde(transparent)] pub struct SessionModeId(pub Arc); impl std::fmt::Display for SessionModeId { @@ -354,24 +361,23 @@ impl std::fmt::Display for SessionModeId { } } -/// **UNSTABLE** -/// -/// This type is not part of the spec, and may be removed or changed at any point. +/// Request parameters for setting a session mode. #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] -#[schemars(extend("x-docs-ignore" = true))] +#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))] #[serde(rename_all = "camelCase")] pub struct SetSessionModeRequest { + /// The ID of the session to set the mode for. pub session_id: SessionId, + /// The ID of the mode to set. pub mode_id: SessionModeId, /// Extension point for implementations #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")] pub meta: Option, } -/// **UNSTABLE** -/// -/// This type is not part of the spec, and may be removed or changed at any point. +/// Response to `session/set_mode` method. #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))] #[serde(rename_all = "camelCase")] pub struct SetSessionModeResponse { pub meta: Option, @@ -614,7 +620,6 @@ pub struct AgentMethodNames { /// Method for loading an existing session. pub session_load: &'static str, /// Method for setting the mode for a session. - #[cfg(feature = "unstable")] pub session_set_mode: &'static str, /// Method for sending a prompt to the agent. pub session_prompt: &'static str, @@ -628,7 +633,6 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames { authenticate: AUTHENTICATE_METHOD_NAME, session_new: SESSION_NEW_METHOD_NAME, session_load: SESSION_LOAD_METHOD_NAME, - #[cfg(feature = "unstable")] session_set_mode: SESSION_SET_MODE_METHOD_NAME, session_prompt: SESSION_PROMPT_METHOD_NAME, session_cancel: SESSION_CANCEL_METHOD_NAME, @@ -643,7 +647,6 @@ pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new"; /// Method name for loading an existing session. pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load"; /// Method name for setting the mode for a session. -#[cfg(feature = "unstable")] pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode"; /// Method name for sending a prompt. pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt"; @@ -664,7 +667,6 @@ pub enum ClientRequest { AuthenticateRequest(AuthenticateRequest), NewSessionRequest(NewSessionRequest), LoadSessionRequest(LoadSessionRequest), - #[cfg(feature = "unstable")] SetSessionModeRequest(SetSessionModeRequest), PromptRequest(PromptRequest), ExtMethodRequest(ExtMethod), @@ -684,7 +686,6 @@ pub enum AgentResponse { AuthenticateResponse(#[serde(default)] AuthenticateResponse), NewSessionResponse(NewSessionResponse), LoadSessionResponse(#[serde(default)] LoadSessionResponse), - #[cfg(feature = "unstable")] SetSessionModeResponse(#[serde(default)] SetSessionModeResponse), PromptResponse(PromptResponse), ExtMethodResponse(#[schemars(with = "serde_json::Value")] Arc), diff --git a/rust/client.rs b/rust/client.rs index 79854a63..b66eb817 100644 --- a/rust/client.rs +++ b/rust/client.rs @@ -10,7 +10,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; -#[cfg(feature = "unstable")] use crate::SessionModeId; use crate::ext::ExtMethod; use crate::{ContentBlock, Error, Plan, SessionId, ToolCall, ToolCallUpdate}; @@ -222,9 +221,8 @@ pub enum SessionUpdate { available_commands: Vec, }, /// The current mode of the session has changed - #[cfg(feature = "unstable")] #[serde(rename_all = "camelCase")] - #[schemars(extend("x-docs-ignore" = true))] + // todo! CurrentModeUpdate { current_mode_id: SessionModeId }, } @@ -425,7 +423,6 @@ pub struct ReadTextFileResponse { #[serde(transparent)] pub struct TerminalId(pub Arc); -#[cfg(feature = "unstable")] impl std::fmt::Display for TerminalId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) diff --git a/rust/rpc_tests.rs b/rust/rpc_tests.rs index 4c400e5e..cf787d81 100644 --- a/rust/rpc_tests.rs +++ b/rust/rpc_tests.rs @@ -207,7 +207,6 @@ impl Agent for TestAgent { }) } - #[cfg(feature = "unstable")] async fn set_session_mode( &self, _arguments: SetSessionModeRequest, diff --git a/rust/tool_call.rs b/rust/tool_call.rs index 95f46a8a..ea1156d3 100644 --- a/rust/tool_call.rs +++ b/rust/tool_call.rs @@ -227,10 +227,7 @@ pub enum ToolKind { Think, /// Retrieving external data. Fetch, - /// **UNSTABLE** - /// - /// This tool kind is not part of the spec and may be removed at any point. - #[cfg(feature = "unstable")] + /// Switching the current session mode. SwitchMode, /// Other tool types (default). #[default] diff --git a/schema/schema.json b/schema/schema.json index 77f8cfea..02a8d318 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -893,7 +893,7 @@ "type": "null" } ], - "description": "**UNSTABLE**\n\nThis field is not part of the spec, and may be removed or changed at any point." + "description": "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)" } }, "type": "object", @@ -1044,7 +1044,7 @@ "type": "null" } ], - "description": "**UNSTABLE**\n\nThis field is not part of the spec, and may be removed or changed at any point." + "description": "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)" }, "sessionId": { "$ref": "#/$defs/SessionId", @@ -1457,7 +1457,7 @@ "type": "string" }, "SessionMode": { - "description": "**UNSTABLE**\n\nThis type is not part of the spec, and may be removed or changed at any point.", + "description": "A mode the agent can operate in.\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", "properties": { "_meta": { "description": "Extension point for implementations" @@ -1476,23 +1476,25 @@ "type": "object" }, "SessionModeId": { - "description": "**UNSTABLE**\n\nThis type is not part of the spec, and may be removed or changed at any point.", + "description": "Unique identifier for a Session Mode.", "type": "string" }, "SessionModeState": { - "description": "**UNSTABLE**\n\nThis type is not part of the spec, and may be removed or changed at any point.", + "description": "The set of modes and the one currently active.", "properties": { "_meta": { "description": "Extension point for implementations" }, "availableModes": { + "description": "The set of modes that the Agent can operate in", "items": { "$ref": "#/$defs/SessionMode" }, "type": "array" }, "currentModeId": { - "$ref": "#/$defs/SessionModeId" + "$ref": "#/$defs/SessionModeId", + "description": "The current mode the Agent is in." } }, "required": ["currentModeId", "availableModes"], @@ -1728,34 +1730,38 @@ } }, "required": ["sessionUpdate", "currentModeId"], - "type": "object", - "x-docs-ignore": true + "type": "object" } ] }, "SetSessionModeRequest": { - "description": "**UNSTABLE**\n\nThis type is not part of the spec, and may be removed or changed at any point.", + "description": "Request parameters for setting a session mode.", "properties": { "_meta": { "description": "Extension point for implementations" }, "modeId": { - "$ref": "#/$defs/SessionModeId" + "$ref": "#/$defs/SessionModeId", + "description": "The ID of the mode to set." }, "sessionId": { - "$ref": "#/$defs/SessionId" + "$ref": "#/$defs/SessionId", + "description": "The ID of the session to set the mode for." } }, "required": ["sessionId", "modeId"], "type": "object", - "x-docs-ignore": true + "x-method": "session/set_mode", + "x-side": "agent" }, "SetSessionModeResponse": { - "description": "**UNSTABLE**\n\nThis type is not part of the spec, and may be removed or changed at any point.", + "description": "Response to `session/set_mode` method.", "properties": { "meta": true }, - "type": "object" + "type": "object", + "x-method": "session/set_mode", + "x-side": "agent" }, "StopReason": { "description": "Reasons why an agent stops processing a prompt turn.\n\nSee protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)", @@ -2159,7 +2165,7 @@ }, { "const": "switch_mode", - "description": "**UNSTABLE**\n\nThis tool kind is not part of the spec and may be removed at any point.", + "description": "Switching the current session mode.", "type": "string" }, { diff --git a/typescript/schema.ts b/typescript/schema.ts index 480a2bc3..a58112cf 100644 --- a/typescript/schema.ts +++ b/typescript/schema.ts @@ -290,30 +290,6 @@ export type McpServer = url: string; } | Stdio; -/** - * **UNSTABLE** - * - * This type is not part of the spec, and may be removed or changed at any point. - */ -export type SessionModeId = string; -/** - * A unique identifier for a conversation session between a client and agent. - * - * Sessions maintain their own context, conversation history, and state, - * allowing multiple independent interactions with the same agent. - * - * # Example - * - * ``` - * use agent_client_protocol::SessionId; - * use std::sync::Arc; - * - * let session_id = SessionId(Arc::from("sess_abc123def456")); - * ``` - * - * See protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session-setup#session-id) - */ -export type SessionId = string; /** * Content blocks represent displayable information in the Agent Client Protocol. * @@ -411,6 +387,10 @@ export type AgentResponse = | SetSessionModeResponse | PromptResponse | ExtMethodResponse1; +/** + * Unique identifier for a Session Mode. + */ +export type SessionModeId = string; /** * All possible notifications that an agent can send to a client. * @@ -1111,9 +1091,7 @@ export interface LoadSessionRequest { sessionId: string; } /** - * **UNSTABLE** - * - * This type is not part of the spec, and may be removed or changed at any point. + * Request parameters for setting a session mode. */ export interface SetSessionModeRequest { /** @@ -1122,8 +1100,14 @@ export interface SetSessionModeRequest { _meta?: { [k: string]: unknown; }; - modeId: SessionModeId; - sessionId: SessionId; + /** + * Unique identifier for a Session Mode. + */ + modeId: string; + /** + * The ID of the session to set the mode for. + */ + sessionId: string; } /** * Request parameters for sending a user prompt to the agent. @@ -1156,21 +1140,7 @@ export interface PromptRequest { */ prompt: ContentBlock[]; /** - * A unique identifier for a conversation session between a client and agent. - * - * Sessions maintain their own context, conversation history, and state, - * allowing multiple independent interactions with the same agent. - * - * # Example - * - * ``` - * use agent_client_protocol::SessionId; - * use std::sync::Arc; - * - * let session_id = SessionId(Arc::from("sess_abc123def456")); - * ``` - * - * See protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session-setup#session-id) + * The ID of the session to send this user message to */ sessionId: string; } @@ -1313,9 +1283,9 @@ export interface NewSessionResponse { [k: string]: unknown; }; /** - * **UNSTABLE** + * Initial mode state if supported by the Agent * - * This field is not part of the spec, and may be removed or changed at any point. + * See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) */ modes?: SessionModeState | null; /** @@ -1326,9 +1296,7 @@ export interface NewSessionResponse { sessionId: string; } /** - * **UNSTABLE** - * - * This type is not part of the spec, and may be removed or changed at any point. + * The set of modes and the one currently active. */ export interface SessionModeState { /** @@ -1337,13 +1305,19 @@ export interface SessionModeState { _meta?: { [k: string]: unknown; }; + /** + * The set of modes that the Agent can operate in + */ availableModes: SessionMode[]; - currentModeId: SessionModeId; + /** + * Unique identifier for a Session Mode. + */ + currentModeId: string; } /** - * **UNSTABLE** + * A mode the agent can operate in. * - * This type is not part of the spec, and may be removed or changed at any point. + * See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) */ export interface SessionMode { /** @@ -1367,16 +1341,14 @@ export interface LoadSessionResponse { [k: string]: unknown; }; /** - * **UNSTABLE** + * Initial mode state if supported by the Agent * - * This field is not part of the spec, and may be removed or changed at any point. + * See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) */ modes?: SessionModeState | null; } /** - * **UNSTABLE** - * - * This type is not part of the spec, and may be removed or changed at any point. + * Response to `session/set_mode` method. */ export interface SetSessionModeResponse { meta?: unknown; @@ -1786,6 +1758,13 @@ export const authenticateRequestSchema = z.object({ methodId: z.string(), }); +/** @internal */ +export const setSessionModeRequestSchema = z.object({ + _meta: z.record(z.unknown()).optional(), + modeId: z.string(), + sessionId: z.string(), +}); + /** @internal */ export const extMethodRequest1Schema = z.record(z.unknown()); @@ -1796,12 +1775,6 @@ export const httpHeaderSchema = z.object({ value: z.string(), }); -/** @internal */ -export const sessionModeIdSchema = z.string(); - -/** @internal */ -export const sessionIdSchema = z.string(); - /** @internal */ export const annotationsSchema = z.object({ _meta: z.record(z.unknown()).optional(), @@ -1841,6 +1814,9 @@ export const promptResponseSchema = z.object({ /** @internal */ export const extMethodResponse1Schema = z.record(z.unknown()); +/** @internal */ +export const sessionModeIdSchema = z.string(); + /** @internal */ export const extNotification1Schema = z.record(z.unknown()); @@ -1973,13 +1949,6 @@ export const mcpServerSchema = z.union([ stdioSchema, ]); -/** @internal */ -export const setSessionModeRequestSchema = z.object({ - _meta: z.record(z.unknown()).optional(), - modeId: sessionModeIdSchema, - sessionId: sessionIdSchema, -}); - /** @internal */ export const contentBlockSchema = z.union([ z.object({ @@ -2057,7 +2026,7 @@ export const sessionModeSchema = z.object({ export const sessionModeStateSchema = z.object({ _meta: z.record(z.unknown()).optional(), availableModes: z.array(sessionModeSchema), - currentModeId: sessionModeIdSchema, + currentModeId: z.string(), }); /** @internal */ From 6d43479d1bc820dc063a3a8f7c47f175d24a8d6b Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Fri, 12 Sep 2025 22:14:24 -0300 Subject: [PATCH 2/2] Update ts docs --- docs/protocol/schema.mdx | 14 ++++++++++++-- docs/protocol/session-modes.mdx | 5 +++-- rust/acp.rs | 1 - rust/example_agent.rs | 8 ++++++++ rust/example_client.rs | 3 ++- rust/rpc_tests.rs | 2 +- typescript/acp.ts | 29 +++++++++++++++++++++++------ 7 files changed, 49 insertions(+), 13 deletions(-) diff --git a/docs/protocol/schema.mdx b/docs/protocol/schema.mdx index 337861de..d6751bfe 100644 --- a/docs/protocol/schema.mdx +++ b/docs/protocol/schema.mdx @@ -389,9 +389,19 @@ See protocol docs: [Check for Completion](https://agentclientprotocol.com/protoc ### session/set_mode -**UNSTABLE** +Sets the current mode for a session. -This method is not part of the spec, and may be removed or changed at any point. +Allows switching between different agent modes (e.g., "ask", "architect", "code") +that affect system prompts, tool availability, and permission behaviors. + +The mode must be one of the modes advertised in `availableModes` during session +creation or loading. Agents may also change modes autonomously and notify the +client via `current_mode_update` notifications. + +This method can be called at any time during a session, whether the Agent is +idle or actively generating a response. + +See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) #### SetSessionModeRequest diff --git a/docs/protocol/session-modes.mdx b/docs/protocol/session-modes.mdx index 233d2102..623ea17c 100644 --- a/docs/protocol/session-modes.mdx +++ b/docs/protocol/session-modes.mdx @@ -32,7 +32,7 @@ During [Session Setup](./session-setup) the Agent **MAY** return a list of modes "id": "code", "name": "Code", "description": "Write and modify code with full tool access" - }, + } ] } } @@ -92,7 +92,8 @@ Typically, Clients display the available modes to the user and allow them to cha - The ID of the mode to switch to. Must be one of the modes listed in `availableModes` + The ID of the mode to switch to. Must be one of the modes listed in + `availableModes` ### From the Agent diff --git a/rust/acp.rs b/rust/acp.rs index caffe4f2..f391cb23 100644 --- a/rust/acp.rs +++ b/rust/acp.rs @@ -684,7 +684,6 @@ impl MessageHandler for T { let response = self.prompt(args).await?; Ok(AgentResponse::PromptResponse(response)) } - #[cfg(feature = "unstable")] ClientRequest::SetSessionModeRequest(args) => { let response = self.set_session_mode(args).await?; Ok(AgentResponse::SetSessionModeResponse(response)) diff --git a/rust/example_agent.rs b/rust/example_agent.rs index 1614e3a0..4e88b7dd 100644 --- a/rust/example_agent.rs +++ b/rust/example_agent.rs @@ -112,6 +112,14 @@ impl acp::Agent for ExampleAgent { Ok(()) } + async fn set_session_mode( + &self, + args: acp::SetSessionModeRequest, + ) -> Result { + log::info!("Received set session mode request {args:?}"); + Ok(Default::default()) + } + async fn ext_method( &self, method: std::sync::Arc, diff --git a/rust/example_client.rs b/rust/example_client.rs index 71e39bde..24688c4c 100644 --- a/rust/example_client.rs +++ b/rust/example_client.rs @@ -97,7 +97,8 @@ impl acp::Client for ExampleClient { | acp::SessionUpdate::AgentThoughtChunk { .. } | acp::SessionUpdate::ToolCall(_) | acp::SessionUpdate::ToolCallUpdate(_) - | acp::SessionUpdate::Plan(_) => {} + | acp::SessionUpdate::Plan(_) + | acp::SessionUpdate::CurrentModeUpdate { .. } => {} } Ok(()) } diff --git a/rust/rpc_tests.rs b/rust/rpc_tests.rs index cf787d81..bd3f6217 100644 --- a/rust/rpc_tests.rs +++ b/rust/rpc_tests.rs @@ -211,7 +211,7 @@ impl Agent for TestAgent { &self, _arguments: SetSessionModeRequest, ) -> Result { - Ok(SetSessionModeResponse {}) + Ok(SetSessionModeResponse { meta: None }) } async fn prompt(&self, arguments: PromptRequest) -> Result { diff --git a/typescript/acp.ts b/typescript/acp.ts index 4a7ffcda..e319872d 100644 --- a/typescript/acp.ts +++ b/typescript/acp.ts @@ -571,12 +571,19 @@ export class ClientSideConnection implements Agent { } /** - * Sets the mode for an existing session. + * Sets the operational mode for a session. * - * This method allows changing the operational mode of an existing session. - * The available modes are advertised in the agent's capabilities during initialization. + * Allows switching between different agent modes (e.g., "ask", "architect", "code") + * that affect system prompts, tool availability, and permission behaviors. * - * See protocol docs: [Session Mode Management](https://agentclientprotocol.com/protocol/session-management#mode-setting) + * The mode must be one of the modes advertised in `availableModes` during session + * creation or loading. Agents may also change modes autonomously and notify the + * client via `current_mode_update` notifications. + * + * This method can be called at any time during a session, whether the Agent is + * idle or actively generating a turn. + * + * See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) */ async setSessionMode( params: schema.SetSessionModeRequest, @@ -1239,9 +1246,19 @@ export interface Agent { params: schema.LoadSessionRequest, ): Promise; /** - * @internal **UNSTABLE** + * Sets the operational mode for a session. + * + * Allows switching between different agent modes (e.g., "ask", "architect", "code") + * that affect system prompts, tool availability, and permission behaviors. + * + * The mode must be one of the modes advertised in `availableModes` during session + * creation or loading. Agents may also change modes autonomously and notify the + * client via `current_mode_update` notifications. + * + * This method can be called at any time during a session, whether the Agent is + * idle or actively generating a turn. * - * This method is not part of the spec, and may be removed or changed at any point. + * See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) */ setSessionMode?( params: schema.SetSessionModeRequest,