Skip to content

Commit 6025456

Browse files
authored
feat(unstable): Add initial support for resuming sessions (#34)
1 parent 538b465 commit 6025456

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

src/agent-client-protocol/src/agent.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use agent_client_protocol_schema::{
1010
use agent_client_protocol_schema::{ForkSessionRequest, ForkSessionResponse};
1111
#[cfg(feature = "unstable_session_list")]
1212
use agent_client_protocol_schema::{ListSessionsRequest, ListSessionsResponse};
13+
#[cfg(feature = "unstable_session_resume")]
14+
use agent_client_protocol_schema::{ResumeSessionRequest, ResumeSessionResponse};
1315
#[cfg(feature = "unstable_session_model")]
1416
use agent_client_protocol_schema::{SetSessionModelRequest, SetSessionModelResponse};
1517
use serde_json::value::RawValue;
@@ -154,6 +156,21 @@ pub trait Agent {
154156
Err(Error::method_not_found())
155157
}
156158

159+
/// **UNSTABLE**
160+
///
161+
/// This capability is not part of the spec yet, and may be removed or changed at any point.
162+
///
163+
/// Resumes an existing session without replaying message history.
164+
///
165+
/// This is similar to `load_session`, except it does not return previous messages.
166+
/// Useful for agents that support continuing conversations but don't store full history.
167+
///
168+
/// Only available if the Agent supports the `sessionCapabilities.resume` capability.
169+
#[cfg(feature = "unstable_session_resume")]
170+
async fn resume_session(&self, _args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
171+
Err(Error::method_not_found())
172+
}
173+
157174
/// Handles extension method requests from the client.
158175
///
159176
/// Extension methods provide a way to add custom functionality while maintaining
@@ -216,6 +233,10 @@ impl<T: Agent> Agent for Rc<T> {
216233
async fn fork_session(&self, args: ForkSessionRequest) -> Result<ForkSessionResponse> {
217234
self.as_ref().fork_session(args).await
218235
}
236+
#[cfg(feature = "unstable_session_resume")]
237+
async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
238+
self.as_ref().resume_session(args).await
239+
}
219240
async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
220241
self.as_ref().ext_method(args).await
221242
}
@@ -265,6 +286,10 @@ impl<T: Agent> Agent for Arc<T> {
265286
async fn fork_session(&self, args: ForkSessionRequest) -> Result<ForkSessionResponse> {
266287
self.as_ref().fork_session(args).await
267288
}
289+
#[cfg(feature = "unstable_session_resume")]
290+
async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
291+
self.as_ref().resume_session(args).await
292+
}
268293
async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
269294
self.as_ref().ext_method(args).await
270295
}

src/agent-client-protocol/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,16 @@ impl Agent for ClientSideConnection {
175175
.await
176176
}
177177

178+
#[cfg(feature = "unstable_session_resume")]
179+
async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
180+
self.conn
181+
.request(
182+
AGENT_METHOD_NAMES.session_resume,
183+
Some(ClientRequest::ResumeSessionRequest(args)),
184+
)
185+
.await
186+
}
187+
178188
async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
179189
self.conn
180190
.request(
@@ -546,6 +556,10 @@ impl Side for AgentSide {
546556
m if m == AGENT_METHOD_NAMES.session_fork => serde_json::from_str(params.get())
547557
.map(ClientRequest::ForkSessionRequest)
548558
.map_err(Into::into),
559+
#[cfg(feature = "unstable_session_resume")]
560+
m if m == AGENT_METHOD_NAMES.session_resume => serde_json::from_str(params.get())
561+
.map(ClientRequest::ResumeSessionRequest)
562+
.map_err(Into::into),
549563
m if m == AGENT_METHOD_NAMES.session_prompt => serde_json::from_str(params.get())
550564
.map(ClientRequest::PromptRequest)
551565
.map_err(Into::into),
@@ -625,6 +639,11 @@ impl<T: Agent> MessageHandler<AgentSide> for T {
625639
let response = self.fork_session(args).await?;
626640
Ok(AgentResponse::ForkSessionResponse(response))
627641
}
642+
#[cfg(feature = "unstable_session_resume")]
643+
ClientRequest::ResumeSessionRequest(args) => {
644+
let response = self.resume_session(args).await?;
645+
Ok(AgentResponse::ResumeSessionResponse(response))
646+
}
628647
ClientRequest::ExtMethodRequest(args) => {
629648
let response = self.ext_method(args).await?;
630649
Ok(AgentResponse::ExtMethodResponse(response))

src/agent-client-protocol/src/rpc_tests.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,18 @@ impl Agent for TestAgent {
240240
))
241241
}
242242

243+
#[cfg(feature = "unstable_session_resume")]
244+
async fn resume_session(
245+
&self,
246+
args: agent_client_protocol_schema::ResumeSessionRequest,
247+
) -> Result<agent_client_protocol_schema::ResumeSessionResponse> {
248+
// Check if session exists
249+
if !self.sessions.lock().unwrap().contains_key(&args.session_id) {
250+
return Err(Error::invalid_params());
251+
}
252+
Ok(agent_client_protocol_schema::ResumeSessionResponse::new())
253+
}
254+
243255
async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
244256
dbg!();
245257
match dbg!(args.method.as_ref()) {
@@ -773,3 +785,37 @@ async fn test_list_sessions() {
773785
})
774786
.await;
775787
}
788+
789+
#[cfg(feature = "unstable_session_resume")]
790+
#[tokio::test]
791+
async fn test_resume_session() {
792+
let local_set = tokio::task::LocalSet::new();
793+
local_set
794+
.run_until(async {
795+
let client = TestClient::new();
796+
let agent = TestAgent::new();
797+
798+
let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
799+
800+
// First create a session
801+
let new_session_response = agent_conn
802+
.new_session(NewSessionRequest::new("/test"))
803+
.await
804+
.expect("new_session failed");
805+
806+
let session_id = new_session_response.session_id;
807+
808+
// Resume the session
809+
let resume_response = agent_conn
810+
.resume_session(agent_client_protocol_schema::ResumeSessionRequest::new(
811+
session_id.clone(),
812+
"/test",
813+
))
814+
.await
815+
.expect("resume_session failed");
816+
817+
// Verify we got a valid response (no modes by default in TestAgent)
818+
assert!(resume_response.modes.is_none());
819+
})
820+
.await;
821+
}

0 commit comments

Comments
 (0)