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
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 10 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,23 @@ name = "client"
path = "rust/example_client.rs"

[dependencies]
anyhow = "1.0"
async-broadcast = "0.7.2"
anyhow = "1"
async-broadcast = "0.7"
async-trait = "0.1"
futures = { version = "0.3" }
log = "0.4"
parking_lot = "0.12"
schemars = { version = "1.0" }
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = { version = "1.0", features = ["raw_value"] }
schemars = { version = "1" }
serde = { version = "1", features = ["derive", "rc"] }
serde_json = { version = "1", features = ["raw_value"] }

[dev-dependencies]
env_logger = "0.11"
futures-util = { version = "0.3", features = ["io"] }
piper = "0.2"
pretty_assertions = "1.4.1"
rustyline = "17.0.1"
tokio-util = { version = "0.7.16", features = ["compat"] }
tokio = { version = "1.0", features = [
pretty_assertions = "1"
rustyline = "17"
tokio = { version = "1", features = [
"macros",
"rt",
"time",
Expand All @@ -59,3 +59,4 @@ tokio = { version = "1.0", features = [
"process",
"sync",
] }
tokio-util = { version = "0.7", features = ["compat"] }
2 changes: 2 additions & 0 deletions rust/acp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ impl ClientSideConnection {
}
}

#[async_trait::async_trait(?Send)]
impl Agent for ClientSideConnection {
async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error> {
self.conn
Expand Down Expand Up @@ -441,6 +442,7 @@ impl AgentSideConnection {
}
}

#[async_trait::async_trait(?Send)]
impl Client for AgentSideConnection {
async fn request_permission(
&self,
Expand Down
33 changes: 11 additions & 22 deletions rust/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
///
/// Agents are programs that use generative AI to autonomously modify code. They handle
/// requests from clients and execute tasks using language models and tools.
#[async_trait::async_trait(?Send)]
pub trait Agent {
/// Establishes the connection with a client and negotiates protocol capabilities.
///
Expand All @@ -31,10 +32,7 @@ pub trait Agent {
/// The agent should respond with its supported protocol version and capabilities.
///
/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
fn initialize(
&self,
args: InitializeRequest,
) -> impl Future<Output = Result<InitializeResponse, Error>>;
async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error>;

/// Authenticates the client using the specified authentication method.
///
Expand All @@ -45,10 +43,7 @@ pub trait Agent {
/// `new_session` without receiving an `auth_required` error.
///
/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
fn authenticate(
&self,
args: AuthenticateRequest,
) -> impl Future<Output = Result<AuthenticateResponse, Error>>;
async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error>;

/// Creates a new conversation session with the agent.
///
Expand All @@ -62,10 +57,7 @@ pub trait Agent {
/// May return an `auth_required` error if the agent requires authentication.
///
/// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
fn new_session(
&self,
args: NewSessionRequest,
) -> impl Future<Output = Result<NewSessionResponse, Error>>;
async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error>;

/// Loads an existing session to resume a previous conversation.
///
Expand All @@ -77,10 +69,7 @@ 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)
fn load_session(
&self,
args: LoadSessionRequest,
) -> impl Future<Output = Result<LoadSessionResponse, Error>>;
async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error>;

/// Sets the current mode for a session.
///
Expand All @@ -95,10 +84,10 @@ pub trait Agent {
/// idle or actively generating a response.
///
/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
fn set_session_mode(
async fn set_session_mode(
&self,
args: SetSessionModeRequest,
) -> impl Future<Output = Result<SetSessionModeResponse, Error>>;
) -> Result<SetSessionModeResponse, Error>;

/// Processes a user prompt within a session.
///
Expand All @@ -111,7 +100,7 @@ pub trait Agent {
/// - Returns when the turn is complete with a stop reason
///
/// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
fn prompt(&self, args: PromptRequest) -> impl Future<Output = Result<PromptResponse, Error>>;
async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error>;

/// Cancels ongoing operations for a session.
///
Expand All @@ -124,23 +113,23 @@ pub trait Agent {
/// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
///
/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
fn cancel(&self, args: CancelNotification) -> impl Future<Output = Result<(), Error>>;
async fn cancel(&self, args: CancelNotification) -> Result<(), Error>;

/// Handles extension method requests from the client.
///
/// Extension methods provide a way to add custom functionality while maintaining
/// protocol compatibility.
///
/// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
fn ext_method(&self, args: ExtRequest) -> impl Future<Output = Result<ExtResponse, Error>>;
async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error>;

/// Handles extension notifications from the client.
///
/// Extension notifications provide a way to send one-way messages for custom functionality
/// while maintaining protocol compatibility.
///
/// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
fn ext_notification(&self, args: ExtNotification) -> impl Future<Output = Result<(), Error>>;
async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error>;
}

// Initialize
Expand Down
42 changes: 20 additions & 22 deletions rust/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{ExtResponse, SessionModeId};
/// Clients are typically code editors (IDEs, text editors) that provide the interface
/// between users and AI agents. They manage the environment, handle user interactions,
/// and control access to resources.
#[async_trait::async_trait(?Send)]
pub trait Client {
/// Requests permission from the user for a tool call operation.
///
Expand All @@ -30,32 +31,32 @@ pub trait Client {
/// respond to this request with `RequestPermissionOutcome::Cancelled`.
///
/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
fn request_permission(
async fn request_permission(
&self,
args: RequestPermissionRequest,
) -> impl Future<Output = Result<RequestPermissionResponse, Error>>;
) -> Result<RequestPermissionResponse, Error>;

/// Writes content to a text file in the client's file system.
///
/// Only available if the client advertises the `fs.writeTextFile` capability.
/// Allows the agent to create or modify files within the client's environment.
///
/// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
fn write_text_file(
async fn write_text_file(
&self,
args: WriteTextFileRequest,
) -> impl Future<Output = Result<WriteTextFileResponse, Error>>;
) -> Result<WriteTextFileResponse, Error>;

/// Reads content from a text file in the client's file system.
///
/// Only available if the client advertises the `fs.readTextFile` capability.
/// Allows the agent to access file contents within the client's environment.
///
/// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
fn read_text_file(
async fn read_text_file(
&self,
args: ReadTextFileRequest,
) -> impl Future<Output = Result<ReadTextFileResponse, Error>>;
) -> Result<ReadTextFileResponse, Error>;

/// Handles session update notifications from the agent.
///
Expand All @@ -68,10 +69,7 @@ pub trait Client {
/// updates before responding with the cancelled stop reason.
///
/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
fn session_notification(
&self,
args: SessionNotification,
) -> impl Future<Output = Result<(), Error>>;
async fn session_notification(&self, args: SessionNotification) -> Result<(), Error>;

/// Executes a command in a new terminal
///
Expand All @@ -87,21 +85,21 @@ pub trait Client {
/// method.
///
/// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
fn create_terminal(
async fn create_terminal(
&self,
args: CreateTerminalRequest,
) -> impl Future<Output = Result<CreateTerminalResponse, Error>>;
) -> Result<CreateTerminalResponse, Error>;

/// Gets the terminal output and exit status
///
/// Returns the current content in the terminal without waiting for the command to exit.
/// If the command has already exited, the exit status is included.
///
/// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
fn terminal_output(
async fn terminal_output(
&self,
args: TerminalOutputRequest,
) -> impl Future<Output = Result<TerminalOutputResponse, Error>>;
) -> Result<TerminalOutputResponse, Error>;

/// Releases a terminal
///
Expand All @@ -115,18 +113,18 @@ pub trait Client {
/// the terminal, allowing the Agent to call `terminal/output` and other methods.
///
/// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
fn release_terminal(
async fn release_terminal(
&self,
args: ReleaseTerminalRequest,
) -> impl Future<Output = Result<ReleaseTerminalResponse, Error>>;
) -> Result<ReleaseTerminalResponse, Error>;

/// Waits for the terminal command to exit and return its exit status
///
/// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
fn wait_for_terminal_exit(
async fn wait_for_terminal_exit(
&self,
args: WaitForTerminalExitRequest,
) -> impl Future<Output = Result<WaitForTerminalExitResponse, Error>>;
) -> Result<WaitForTerminalExitResponse, Error>;

/// Kills the terminal command without releasing the terminal
///
Expand All @@ -140,10 +138,10 @@ pub trait Client {
/// Note: `terminal/release` when `TerminalId` is no longer needed.
///
/// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
fn kill_terminal_command(
async fn kill_terminal_command(
&self,
args: KillTerminalCommandRequest,
) -> impl Future<Output = Result<KillTerminalCommandResponse, Error>>;
) -> Result<KillTerminalCommandResponse, Error>;

/// Handles extension method requests from the agent.
///
Expand All @@ -152,7 +150,7 @@ pub trait Client {
/// protocol compatibility.
///
/// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
fn ext_method(&self, args: ExtRequest) -> impl Future<Output = Result<ExtResponse, Error>>;
async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error>;

/// Handles extension notifications from the agent.
///
Expand All @@ -161,7 +159,7 @@ pub trait Client {
/// while maintaining protocol compatibility.
///
/// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
fn ext_notification(&self, args: ExtNotification) -> impl Future<Output = Result<(), Error>>;
async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error>;
}

// Session updates
Expand Down
1 change: 1 addition & 0 deletions rust/example_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ impl ExampleAgent {
}
}

#[async_trait::async_trait(?Send)]
impl acp::Agent for ExampleAgent {
async fn initialize(
&self,
Expand Down
1 change: 1 addition & 0 deletions rust/example_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};

struct ExampleClient {}

#[async_trait::async_trait(?Send)]
impl acp::Client for ExampleClient {
async fn request_permission(
&self,
Expand Down
2 changes: 2 additions & 0 deletions rust/rpc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ macro_rules! raw_json {
}};
}

#[async_trait::async_trait(?Send)]
impl Client for TestClient {
async fn request_permission(
&self,
Expand Down Expand Up @@ -162,6 +163,7 @@ impl TestAgent {
}
}

#[async_trait::async_trait(?Send)]
impl Agent for TestAgent {
async fn initialize(&self, arguments: InitializeRequest) -> Result<InitializeResponse, Error> {
Ok(InitializeResponse {
Expand Down