From bc8ccd29d0af5ac0bc9defe187a7d5c987267b0e Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Tue, 30 Sep 2025 16:09:04 +0200 Subject: [PATCH] Correctly treat capability-based methods as optional in SDKs --- CHANGELOG.md | 14 +++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- package-lock.json | 4 +-- package.json | 2 +- rust/agent.rs | 76 +++++++++++++++++++++++++++-------------------- rust/client.rs | 76 +++++++++++++++++++++++++++++------------------ typescript/acp.ts | 8 ++--- 8 files changed, 113 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dae9a9a5..e00e760d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 0.4.4 (2025-09-30) + +### Protocol + +- No changes + +### Rust + +- Provide default trait implementations for optional capability-based `Agent` and `Client` methods. + +### Typescript + +- Correctly mark capability-based `Agent` and `Client` methods as optional. + ## 0.4.3 (2025-09-25) ### Protocol diff --git a/Cargo.lock b/Cargo.lock index b44e9d34..11fb8d87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,7 +19,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "agent-client-protocol" -version = "0.4.3" +version = "0.4.4" dependencies = [ "anyhow", "async-broadcast", diff --git a/Cargo.toml b/Cargo.toml index a4d4211d..56ee3ff3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "agent-client-protocol" authors = ["Zed "] -version = "0.4.3" +version = "0.4.4" edition = "2024" license = "Apache-2.0" description = "A protocol for standardizing communication between code editors and AI coding agents" diff --git a/package-lock.json b/package-lock.json index b1a48072..47844d86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@zed-industries/agent-client-protocol", - "version": "0.4.3", + "version": "0.4.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@zed-industries/agent-client-protocol", - "version": "0.4.3", + "version": "0.4.4", "license": "Apache-2.0", "dependencies": { "zod": "^3.0.0" diff --git a/package.json b/package.json index d55a3228..954968b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zed-industries/agent-client-protocol", - "version": "0.4.3", + "version": "0.4.4", "publishConfig": { "access": "public" }, diff --git a/rust/agent.rs b/rust/agent.rs index 70a732d8..e5ed5d60 100644 --- a/rust/agent.rs +++ b/rust/agent.rs @@ -60,6 +60,32 @@ pub trait Agent { /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup) async fn new_session(&self, args: NewSessionRequest) -> Result; + /// Processes a user prompt within a session. + /// + /// This method handles the whole lifecycle of a prompt: + /// - Receives user messages with optional context (files, images, etc.) + /// - Processes the prompt using language models + /// - Reports language model content and tool calls to the Clients + /// - Requests permission to run tools + /// - Executes any requested tool calls + /// - Returns when the turn is complete with a stop reason + /// + /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn) + async fn prompt(&self, args: PromptRequest) -> Result; + + /// Cancels ongoing operations for a session. + /// + /// This is a notification sent by the client to cancel an ongoing prompt turn. + /// + /// Upon receiving this notification, the Agent SHOULD: + /// - Stop all language model requests as soon as possible + /// - Abort all tool call invocations in progress + /// - Send any pending `session/update` notifications + /// - Respond to the original `session/prompt` request with `StopReason::Cancelled` + /// + /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) + async fn cancel(&self, args: CancelNotification) -> Result<(), Error>; + /// Loads an existing session to resume a previous conversation. /// /// This method is only available if the agent advertises the `loadSession` capability. @@ -70,7 +96,9 @@ pub trait Agent { /// - Stream the entire conversation history back to the client via notifications /// /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions) - async fn load_session(&self, args: LoadSessionRequest) -> Result; + async fn load_session(&self, _args: LoadSessionRequest) -> Result { + Err(Error::method_not_found()) + } /// Sets the current mode for a session. /// @@ -87,34 +115,10 @@ pub trait Agent { /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) async fn set_session_mode( &self, - args: SetSessionModeRequest, - ) -> Result; - - /// Processes a user prompt within a session. - /// - /// This method handles the whole lifecycle of a prompt: - /// - Receives user messages with optional context (files, images, etc.) - /// - Processes the prompt using language models - /// - Reports language model content and tool calls to the Clients - /// - Requests permission to run tools - /// - Executes any requested tool calls - /// - Returns when the turn is complete with a stop reason - /// - /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn) - async fn prompt(&self, args: PromptRequest) -> Result; - - /// Cancels ongoing operations for a session. - /// - /// This is a notification sent by the client to cancel an ongoing prompt turn. - /// - /// Upon receiving this notification, the Agent SHOULD: - /// - Stop all language model requests as soon as possible - /// - Abort all tool call invocations in progress - /// - Send any pending `session/update` notifications - /// - Respond to the original `session/prompt` request with `StopReason::Cancelled` - /// - /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) - async fn cancel(&self, args: CancelNotification) -> Result<(), Error>; + _args: SetSessionModeRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// **UNSTABLE** /// @@ -124,8 +128,10 @@ pub trait Agent { #[cfg(feature = "unstable")] async fn set_session_model( &self, - args: SetSessionModelRequest, - ) -> Result; + _args: SetSessionModelRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Handles extension method requests from the client. /// @@ -133,7 +139,9 @@ pub trait Agent { /// protocol compatibility. /// /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - async fn ext_method(&self, args: ExtRequest) -> Result; + async fn ext_method(&self, _args: ExtRequest) -> Result { + Ok(RawValue::NULL.to_owned().into()) + } /// Handles extension notifications from the client. /// @@ -141,7 +149,9 @@ pub trait Agent { /// while maintaining protocol compatibility. /// /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error>; + async fn ext_notification(&self, _args: ExtNotification) -> Result<(), Error> { + Ok(()) + } } #[async_trait::async_trait(?Send)] diff --git a/rust/client.rs b/rust/client.rs index 15d589bc..61264441 100644 --- a/rust/client.rs +++ b/rust/client.rs @@ -37,6 +37,19 @@ pub trait Client { args: RequestPermissionRequest, ) -> Result; + /// Handles session update notifications from the agent. + /// + /// This is a notification endpoint (no response expected) that receives + /// real-time updates about session progress, including message chunks, + /// tool calls, and execution plans. + /// + /// Note: Clients SHOULD continue accepting tool call updates even after + /// sending a `session/cancel` notification, as the agent may send final + /// updates before responding with the cancelled stop reason. + /// + /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) + async fn session_notification(&self, args: SessionNotification) -> Result<(), Error>; + /// Writes content to a text file in the client's file system. /// /// Only available if the client advertises the `fs.writeTextFile` capability. @@ -45,8 +58,10 @@ pub trait Client { /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) async fn write_text_file( &self, - args: WriteTextFileRequest, - ) -> Result; + _args: WriteTextFileRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Reads content from a text file in the client's file system. /// @@ -56,21 +71,10 @@ pub trait Client { /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) async fn read_text_file( &self, - args: ReadTextFileRequest, - ) -> Result; - - /// Handles session update notifications from the agent. - /// - /// This is a notification endpoint (no response expected) that receives - /// real-time updates about session progress, including message chunks, - /// tool calls, and execution plans. - /// - /// Note: Clients SHOULD continue accepting tool call updates even after - /// sending a `session/cancel` notification, as the agent may send final - /// updates before responding with the cancelled stop reason. - /// - /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) - async fn session_notification(&self, args: SessionNotification) -> Result<(), Error>; + _args: ReadTextFileRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Executes a command in a new terminal /// @@ -88,8 +92,10 @@ pub trait Client { /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) async fn create_terminal( &self, - args: CreateTerminalRequest, - ) -> Result; + _args: CreateTerminalRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Gets the terminal output and exit status /// @@ -99,8 +105,10 @@ pub trait Client { /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) async fn terminal_output( &self, - args: TerminalOutputRequest, - ) -> Result; + _args: TerminalOutputRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Releases a terminal /// @@ -116,16 +124,20 @@ pub trait Client { /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) async fn release_terminal( &self, - args: ReleaseTerminalRequest, - ) -> Result; + _args: ReleaseTerminalRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Waits for the terminal command to exit and return its exit status /// /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) async fn wait_for_terminal_exit( &self, - args: WaitForTerminalExitRequest, - ) -> Result; + _args: WaitForTerminalExitRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Kills the terminal command without releasing the terminal /// @@ -141,8 +153,10 @@ pub trait Client { /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) async fn kill_terminal_command( &self, - args: KillTerminalCommandRequest, - ) -> Result; + _args: KillTerminalCommandRequest, + ) -> Result { + Err(Error::method_not_found()) + } /// Handles extension method requests from the agent. /// @@ -151,7 +165,9 @@ pub trait Client { /// protocol compatibility. /// /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - async fn ext_method(&self, args: ExtRequest) -> Result; + async fn ext_method(&self, _args: ExtRequest) -> Result { + Ok(RawValue::NULL.to_owned().into()) + } /// Handles extension notifications from the agent. /// @@ -160,7 +176,9 @@ pub trait Client { /// while maintaining protocol compatibility. /// /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error>; + async fn ext_notification(&self, _args: ExtNotification) -> Result<(), Error> { + Ok(()) + } } #[async_trait::async_trait(?Send)] diff --git a/typescript/acp.ts b/typescript/acp.ts index 0c93c42e..818baab5 100644 --- a/typescript/acp.ts +++ b/typescript/acp.ts @@ -399,14 +399,14 @@ export class ClientSideConnection implements Agent { case schema.CLIENT_METHODS.fs_write_text_file: { const validatedParams = schema.writeTextFileRequestSchema.parse(params); - return client.writeTextFile( + return client.writeTextFile?.( validatedParams as schema.WriteTextFileRequest, ); } case schema.CLIENT_METHODS.fs_read_text_file: { const validatedParams = schema.readTextFileRequestSchema.parse(params); - return client.readTextFile( + return client.readTextFile?.( validatedParams as schema.ReadTextFileRequest, ); } @@ -1034,7 +1034,7 @@ export interface Client { * * See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) */ - writeTextFile( + writeTextFile?( params: schema.WriteTextFileRequest, ): Promise; /** @@ -1045,7 +1045,7 @@ export interface Client { * * See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) */ - readTextFile( + readTextFile?( params: schema.ReadTextFileRequest, ): Promise;