agent_client_protocol/concepts/sessions.rs
1//! Creating and managing sessions for multi-turn conversations.
2//!
3//! A **session** represents a multi-turn conversation with an agent. Within a
4//! session, you can send prompts, receive responses, and the agent maintains
5//! context across turns.
6//!
7//! # Creating a Session
8//!
9//! Use the session builder to create a new session:
10//!
11//! ```
12//! # use agent_client_protocol::{Client, Agent, ConnectTo};
13//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
14//! # Client.builder().connect_with(transport, async |cx| {
15//! cx.build_session_cwd()? // Use current working directory
16//! .block_task() // Mark as blocking
17//! .run_until(async |session| {
18//! // Use the session here
19//! Ok(())
20//! })
21//! .await?;
22//! # Ok(())
23//! # }).await?;
24//! # Ok(())
25//! # }
26//! ```
27//!
28//! Or specify a custom working directory:
29//!
30//! ```
31//! # use agent_client_protocol::{Client, Agent, ConnectTo};
32//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
33//! # Client.builder().connect_with(transport, async |cx| {
34//! cx.build_session("/path/to/project")
35//! .block_task()
36//! .run_until(async |session| { Ok(()) })
37//! .await?;
38//! # Ok(())
39//! # }).await?;
40//! # Ok(())
41//! # }
42//! ```
43//!
44//! # Sending Prompts
45//!
46//! Inside `run_until`, you get an [`ActiveSession`] that lets you interact
47//! with the agent:
48//!
49//! ```
50//! # use agent_client_protocol::{Client, Agent, ConnectTo};
51//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
52//! # Client.builder().connect_with(transport, async |cx| {
53//! # cx.build_session_cwd()?.block_task()
54//! .run_until(async |mut session| {
55//! // Send a prompt
56//! session.send_prompt("What is 2 + 2?")?;
57//!
58//! // Read the complete response as a string
59//! let response = session.read_to_string().await?;
60//! println!("{}", response);
61//!
62//! // Send another prompt in the same session
63//! session.send_prompt("And what is 3 + 3?")?;
64//! let response = session.read_to_string().await?;
65//!
66//! Ok(())
67//! })
68//! # .await?;
69//! # Ok(())
70//! # }).await?;
71//! # Ok(())
72//! # }
73//! ```
74//!
75//! # Adding MCP Servers
76//!
77//! You can attach MCP (Model Context Protocol) servers to a session to provide
78//! tools to the agent:
79//!
80//! ```
81//! # use agent_client_protocol::{Client, Agent, ConnectTo};
82//! # use agent_client_protocol::mcp_server::McpServer;
83//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
84//! # let my_mcp_server = McpServer::<Agent, _>::builder("tools").build();
85//! # Client.builder().connect_with(transport, async |cx| {
86//! cx.build_session_cwd()?
87//! .with_mcp_server(my_mcp_server)?
88//! .block_task()
89//! .run_until(async |session| { Ok(()) })
90//! .await?;
91//! # Ok(())
92//! # }).await?;
93//! # Ok(())
94//! # }
95//! ```
96//!
97//! See the cookbook for detailed MCP server examples.
98//!
99//! # Non-Blocking Session Start
100//!
101//! If you're inside an `on_receive_*` callback and need to start a session,
102//! use `on_session_start` instead of `block_task().run_until()`:
103//!
104//! ```
105//! # use agent_client_protocol::{Client, Agent, ConnectTo};
106//! # use agent_client_protocol::schema::NewSessionRequest;
107//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
108//! Client.builder()
109//! .on_receive_request(async |req: NewSessionRequest, responder, cx| {
110//! cx.build_session_from(req)
111//! .on_session_start(async |session| {
112//! // Handle the session
113//! Ok(())
114//! })?;
115//! Ok(())
116//! }, agent_client_protocol::on_receive_request!())
117//! # .connect_with(transport, async |_| Ok(())).await?;
118//! # Ok(())
119//! # }
120//! ```
121//!
122//! This follows the same ordering guarantees as other `on_*` methods - see
123//! [Ordering](super::ordering) for details.
124//!
125//! # Next Steps
126//!
127//! - [Callbacks](super::callbacks) - Handle incoming requests
128//! - [Ordering](super::ordering) - Understand when to use `block_task` vs `on_*`
129//!
130//! [`ActiveSession`]: crate::ActiveSession